1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef V8_HYDROGEN_INSTRUCTIONS_H_
6 #define V8_HYDROGEN_INSTRUCTIONS_H_
13 #include "src/allocation.h"
14 #include "src/base/bits.h"
15 #include "src/bit-vector.h"
16 #include "src/code-stubs.h"
17 #include "src/conversions.h"
18 #include "src/deoptimizer.h"
19 #include "src/hydrogen-types.h"
20 #include "src/small-pointer-list.h"
21 #include "src/unique.h"
22 #include "src/utils.h"
28 // Forward declarations.
33 class HInferRepresentationPhase;
35 class HLoopInformation;
36 class HStoreNamedField;
41 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
42 V(ArithmeticBinaryOperation) \
44 V(BitwiseBinaryOperation) \
45 V(ControlInstruction) \
49 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
51 V(AccessArgumentsAt) \
53 V(AllocateBlockContext) \
56 V(ArgumentsElements) \
62 V(BoundsCheckBaseIndexInformation) \
64 V(CallWithDescriptor) \
74 V(CheckInstanceType) \
80 V(ClassOfTestAndBranch) \
81 V(CompareNumericAndBranch) \
82 V(CompareHoleAndBranch) \
84 V(CompareMinusZeroAndBranch) \
85 V(CompareObjectEqAndBranch) \
98 V(EnvironmentMarker) \
99 V(ForceRepresentation) \
103 V(GetCachedArrayIndex) \
105 V(HasCachedArrayIndexAndBranch) \
106 V(HasInstanceTypeAndBranch) \
107 V(InnerAllocatedObject) \
109 V(InstanceOfKnownGlobal) \
111 V(IsConstructCallAndBranch) \
112 V(IsObjectAndBranch) \
113 V(IsStringAndBranch) \
115 V(IsUndetectableAndBranch) \
118 V(LoadFieldByIndex) \
119 V(LoadFunctionPrototype) \
120 V(LoadGlobalGeneric) \
122 V(LoadKeyedGeneric) \
124 V(LoadNamedGeneric) \
139 V(SeqStringGetChar) \
140 V(SeqStringSetChar) \
146 V(StoreContextSlot) \
147 V(StoreFrameContext) \
149 V(StoreKeyedGeneric) \
151 V(StoreNamedGeneric) \
153 V(StringCharCodeAt) \
154 V(StringCharFromCode) \
155 V(StringCompareAndBranch) \
157 V(TailCallThroughMegamorphicCache) \
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); \
968 // A helper class to represent per-operand position information attached to
969 // the HInstruction in the compact form. Uses tagging to distinguish between
970 // case when only instruction's position is available and case when operands'
971 // positions are also available.
972 // In the first case it contains intruction's position as a tagged value.
973 // In the second case it points to an array which contains instruction's
974 // position and operands' positions.
975 class HPositionInfo {
977 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
979 SourcePosition position() const {
980 if (has_operand_positions()) {
981 return operand_positions()[kInstructionPosIndex];
983 return SourcePosition::FromRaw(static_cast<int>(UntagPosition(data_)));
986 void set_position(SourcePosition pos) {
987 if (has_operand_positions()) {
988 operand_positions()[kInstructionPosIndex] = pos;
990 data_ = TagPosition(pos.raw());
994 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
995 if (has_operand_positions()) {
999 const int length = kFirstOperandPosIndex + operand_count;
1000 SourcePosition* positions = zone->NewArray<SourcePosition>(length);
1001 for (int i = 0; i < length; i++) {
1002 positions[i] = SourcePosition::Unknown();
1005 const SourcePosition pos = position();
1006 data_ = reinterpret_cast<intptr_t>(positions);
1009 DCHECK(has_operand_positions());
1012 SourcePosition operand_position(int idx) const {
1013 if (!has_operand_positions()) {
1016 return *operand_position_slot(idx);
1019 void set_operand_position(int idx, SourcePosition pos) {
1020 *operand_position_slot(idx) = pos;
1024 static const intptr_t kInstructionPosIndex = 0;
1025 static const intptr_t kFirstOperandPosIndex = 1;
1027 SourcePosition* operand_position_slot(int idx) const {
1028 DCHECK(has_operand_positions());
1029 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1032 bool has_operand_positions() const {
1033 return !IsTaggedPosition(data_);
1036 SourcePosition* operand_positions() const {
1037 DCHECK(has_operand_positions());
1038 return reinterpret_cast<SourcePosition*>(data_);
1041 static const intptr_t kPositionTag = 1;
1042 static const intptr_t kPositionShift = 1;
1043 static bool IsTaggedPosition(intptr_t val) {
1044 return (val & kPositionTag) != 0;
1046 static intptr_t UntagPosition(intptr_t val) {
1047 DCHECK(IsTaggedPosition(val));
1048 return val >> kPositionShift;
1050 static intptr_t TagPosition(intptr_t val) {
1051 const intptr_t result = (val << kPositionShift) | kPositionTag;
1052 DCHECK(UntagPosition(result) == val);
1060 class HInstruction : public HValue {
1062 HInstruction* next() const { return next_; }
1063 HInstruction* previous() const { return previous_; }
1065 std::ostream& PrintTo(std::ostream& os) const OVERRIDE; // NOLINT
1066 virtual std::ostream& PrintDataTo(std::ostream& os) const; // NOLINT
1068 bool IsLinked() const { return block() != NULL; }
1071 void InsertBefore(HInstruction* next);
1073 template<class T> T* Prepend(T* instr) {
1074 instr->InsertBefore(this);
1078 void InsertAfter(HInstruction* previous);
1080 template<class T> T* Append(T* instr) {
1081 instr->InsertAfter(this);
1085 // The position is a write-once variable.
1086 SourcePosition position() const OVERRIDE {
1087 return SourcePosition(position_.position());
1089 bool has_position() const {
1090 return !position().IsUnknown();
1092 void set_position(SourcePosition position) {
1093 DCHECK(!has_position());
1094 DCHECK(!position.IsUnknown());
1095 position_.set_position(position);
1098 SourcePosition operand_position(int index) const OVERRIDE {
1099 const SourcePosition pos = position_.operand_position(index);
1100 return pos.IsUnknown() ? position() : pos;
1102 void set_operand_position(Zone* zone, int index, SourcePosition pos) {
1103 DCHECK(0 <= index && index < OperandCount());
1104 position_.ensure_storage_for_operand_positions(zone, OperandCount());
1105 position_.set_operand_position(index, pos);
1108 bool Dominates(HInstruction* other);
1109 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1110 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1112 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1115 void Verify() OVERRIDE;
1118 bool CanDeoptimize();
1120 virtual bool HasStackCheck() { return false; }
1122 DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1125 explicit HInstruction(HType type = HType::Tagged())
1129 position_(RelocInfo::kNoPosition) {
1130 SetDependsOnFlag(kOsrEntries);
1133 void DeleteFromGraph() OVERRIDE { Unlink(); }
1136 void InitializeAsFirst(HBasicBlock* block) {
1137 DCHECK(!IsLinked());
1141 HInstruction* next_;
1142 HInstruction* previous_;
1143 HPositionInfo position_;
1145 friend class HBasicBlock;
1150 class HTemplateInstruction : public HInstruction {
1152 int OperandCount() const FINAL { return V; }
1153 HValue* OperandAt(int i) const FINAL { return inputs_[i]; }
1156 explicit HTemplateInstruction(HType type = HType::Tagged())
1157 : HInstruction(type) {}
1159 void InternalSetOperandAt(int i, HValue* value) FINAL { inputs_[i] = value; }
1162 EmbeddedContainer<HValue*, V> inputs_;
1166 class HControlInstruction : public HInstruction {
1168 virtual HBasicBlock* SuccessorAt(int i) const = 0;
1169 virtual int SuccessorCount() const = 0;
1170 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1172 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1174 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1179 HBasicBlock* FirstSuccessor() {
1180 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1182 HBasicBlock* SecondSuccessor() {
1183 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1187 HBasicBlock* swap = SuccessorAt(0);
1188 SetSuccessorAt(0, SuccessorAt(1));
1189 SetSuccessorAt(1, swap);
1192 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1196 class HSuccessorIterator FINAL BASE_EMBEDDED {
1198 explicit HSuccessorIterator(const HControlInstruction* instr)
1199 : instr_(instr), current_(0) {}
1201 bool Done() { return current_ >= instr_->SuccessorCount(); }
1202 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1203 void Advance() { current_++; }
1206 const HControlInstruction* instr_;
1211 template<int S, int V>
1212 class HTemplateControlInstruction : public HControlInstruction {
1214 int SuccessorCount() const OVERRIDE { return S; }
1215 HBasicBlock* SuccessorAt(int i) const OVERRIDE { return successors_[i]; }
1216 void SetSuccessorAt(int i, HBasicBlock* block) OVERRIDE {
1217 successors_[i] = block;
1220 int OperandCount() const OVERRIDE { return V; }
1221 HValue* OperandAt(int i) const OVERRIDE { return inputs_[i]; }
1225 void InternalSetOperandAt(int i, HValue* value) OVERRIDE {
1230 EmbeddedContainer<HBasicBlock*, S> successors_;
1231 EmbeddedContainer<HValue*, V> inputs_;
1235 class HBlockEntry FINAL : public HTemplateInstruction<0> {
1237 Representation RequiredInputRepresentation(int index) OVERRIDE {
1238 return Representation::None();
1241 DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1245 class HDummyUse FINAL : public HTemplateInstruction<1> {
1247 explicit HDummyUse(HValue* value)
1248 : HTemplateInstruction<1>(HType::Smi()) {
1249 SetOperandAt(0, value);
1250 // Pretend to be a Smi so that the HChange instructions inserted
1251 // before any use generate as little code as possible.
1252 set_representation(Representation::Tagged());
1255 HValue* value() const { return OperandAt(0); }
1257 bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
1258 Representation RequiredInputRepresentation(int index) OVERRIDE {
1259 return Representation::None();
1262 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1264 DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1268 // Inserts an int3/stop break instruction for debugging purposes.
1269 class HDebugBreak FINAL : public HTemplateInstruction<0> {
1271 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1273 Representation RequiredInputRepresentation(int index) OVERRIDE {
1274 return Representation::None();
1277 DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1281 class HGoto FINAL : public HTemplateControlInstruction<1, 0> {
1283 explicit HGoto(HBasicBlock* target) {
1284 SetSuccessorAt(0, target);
1287 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1288 *block = FirstSuccessor();
1292 Representation RequiredInputRepresentation(int index) OVERRIDE {
1293 return Representation::None();
1296 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1298 DECLARE_CONCRETE_INSTRUCTION(Goto)
1302 class HDeoptimize FINAL : public HTemplateControlInstruction<1, 0> {
1304 static HDeoptimize* New(Isolate* isolate, Zone* zone, HValue* context,
1305 Deoptimizer::DeoptReason reason,
1306 Deoptimizer::BailoutType type,
1307 HBasicBlock* unreachable_continuation) {
1308 return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1311 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1316 Representation RequiredInputRepresentation(int index) OVERRIDE {
1317 return Representation::None();
1320 Deoptimizer::DeoptReason reason() const { return reason_; }
1321 Deoptimizer::BailoutType type() { return type_; }
1323 DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1326 explicit HDeoptimize(Deoptimizer::DeoptReason reason,
1327 Deoptimizer::BailoutType type,
1328 HBasicBlock* unreachable_continuation)
1329 : reason_(reason), type_(type) {
1330 SetSuccessorAt(0, unreachable_continuation);
1333 Deoptimizer::DeoptReason reason_;
1334 Deoptimizer::BailoutType type_;
1338 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1340 HUnaryControlInstruction(HValue* value,
1341 HBasicBlock* true_target,
1342 HBasicBlock* false_target) {
1343 SetOperandAt(0, value);
1344 SetSuccessorAt(0, true_target);
1345 SetSuccessorAt(1, false_target);
1348 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1350 HValue* value() const { return OperandAt(0); }
1354 class HBranch FINAL : public HUnaryControlInstruction {
1356 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1357 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1358 ToBooleanStub::Types);
1359 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1360 ToBooleanStub::Types,
1361 HBasicBlock*, HBasicBlock*);
1363 Representation RequiredInputRepresentation(int index) OVERRIDE {
1364 return Representation::None();
1366 Representation observed_input_representation(int index) OVERRIDE;
1368 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
1370 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1372 ToBooleanStub::Types expected_input_types() const {
1373 return expected_input_types_;
1376 DECLARE_CONCRETE_INSTRUCTION(Branch)
1379 HBranch(HValue* value,
1380 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1381 HBasicBlock* true_target = NULL,
1382 HBasicBlock* false_target = NULL)
1383 : HUnaryControlInstruction(value, true_target, false_target),
1384 expected_input_types_(expected_input_types) {
1385 SetFlag(kAllowUndefinedAsNaN);
1388 ToBooleanStub::Types expected_input_types_;
1392 class HCompareMap FINAL : public HUnaryControlInstruction {
1394 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1395 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1396 HBasicBlock*, HBasicBlock*);
1398 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE {
1399 if (known_successor_index() != kNoKnownSuccessorIndex) {
1400 *block = SuccessorAt(known_successor_index());
1407 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1409 static const int kNoKnownSuccessorIndex = -1;
1410 int known_successor_index() const {
1411 return KnownSuccessorIndexField::decode(bit_field_) -
1412 kInternalKnownSuccessorOffset;
1414 void set_known_successor_index(int index) {
1415 DCHECK(index >= 0 - kInternalKnownSuccessorOffset);
1416 bit_field_ = KnownSuccessorIndexField::update(
1417 bit_field_, index + kInternalKnownSuccessorOffset);
1420 Unique<Map> map() const { return map_; }
1421 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
1423 Representation RequiredInputRepresentation(int index) OVERRIDE {
1424 return Representation::Tagged();
1427 DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1430 int RedefinedOperandIndex() OVERRIDE { return 0; }
1433 HCompareMap(HValue* value, Handle<Map> map, HBasicBlock* true_target = NULL,
1434 HBasicBlock* false_target = NULL)
1435 : HUnaryControlInstruction(value, true_target, false_target),
1436 bit_field_(KnownSuccessorIndexField::encode(
1437 kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset) |
1438 MapIsStableField::encode(map->is_stable())),
1439 map_(Unique<Map>::CreateImmovable(map)) {
1440 set_representation(Representation::Tagged());
1443 // BitFields can only store unsigned values, so use an offset.
1444 // Adding kInternalKnownSuccessorOffset must yield an unsigned value.
1445 static const int kInternalKnownSuccessorOffset = 1;
1446 STATIC_ASSERT(kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset >= 0);
1448 class KnownSuccessorIndexField : public BitField<int, 0, 31> {};
1449 class MapIsStableField : public BitField<bool, 31, 1> {};
1451 uint32_t bit_field_;
1456 class HContext FINAL : public HTemplateInstruction<0> {
1458 static HContext* New(Zone* zone) {
1459 return new(zone) HContext();
1462 Representation RequiredInputRepresentation(int index) OVERRIDE {
1463 return Representation::None();
1466 DECLARE_CONCRETE_INSTRUCTION(Context)
1469 bool DataEquals(HValue* other) OVERRIDE { return true; }
1473 set_representation(Representation::Tagged());
1477 bool IsDeletable() const OVERRIDE { return true; }
1481 class HReturn FINAL : public HTemplateControlInstruction<0, 3> {
1483 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1484 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1486 Representation RequiredInputRepresentation(int index) OVERRIDE {
1487 // TODO(titzer): require an Int32 input for faster returns.
1488 if (index == 2) return Representation::Smi();
1489 return Representation::Tagged();
1492 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1494 HValue* value() const { return OperandAt(0); }
1495 HValue* context() const { return OperandAt(1); }
1496 HValue* parameter_count() const { return OperandAt(2); }
1498 DECLARE_CONCRETE_INSTRUCTION(Return)
1501 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1502 SetOperandAt(0, value);
1503 SetOperandAt(1, context);
1504 SetOperandAt(2, parameter_count);
1509 class HAbnormalExit FINAL : public HTemplateControlInstruction<0, 0> {
1511 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1513 Representation RequiredInputRepresentation(int index) OVERRIDE {
1514 return Representation::None();
1517 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1523 class HUnaryOperation : public HTemplateInstruction<1> {
1525 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1526 : HTemplateInstruction<1>(type) {
1527 SetOperandAt(0, value);
1530 static HUnaryOperation* cast(HValue* value) {
1531 return reinterpret_cast<HUnaryOperation*>(value);
1534 HValue* value() const { return OperandAt(0); }
1535 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1539 class HUseConst FINAL : public HUnaryOperation {
1541 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1543 Representation RequiredInputRepresentation(int index) OVERRIDE {
1544 return Representation::None();
1547 DECLARE_CONCRETE_INSTRUCTION(UseConst)
1550 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1554 class HForceRepresentation FINAL : public HTemplateInstruction<1> {
1556 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
1558 Representation required_representation);
1560 HValue* value() const { return OperandAt(0); }
1562 Representation observed_input_representation(int index) OVERRIDE {
1563 // We haven't actually *observed* this, but it's closer to the truth
1565 return representation(); // Same as the output representation.
1567 Representation RequiredInputRepresentation(int index) OVERRIDE {
1568 return representation(); // Same as the output representation.
1571 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1573 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1576 HForceRepresentation(HValue* value, Representation required_representation) {
1577 SetOperandAt(0, value);
1578 set_representation(required_representation);
1583 class HChange FINAL : public HUnaryOperation {
1585 HChange(HValue* value,
1587 bool is_truncating_to_smi,
1588 bool is_truncating_to_int32)
1589 : HUnaryOperation(value) {
1590 DCHECK(!value->representation().IsNone());
1591 DCHECK(!to.IsNone());
1592 DCHECK(!value->representation().Equals(to));
1593 set_representation(to);
1595 SetFlag(kCanOverflow);
1596 if (is_truncating_to_smi && to.IsSmi()) {
1597 SetFlag(kTruncatingToSmi);
1598 SetFlag(kTruncatingToInt32);
1600 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1601 if (value->representation().IsSmi() || value->type().IsSmi()) {
1602 set_type(HType::Smi());
1604 set_type(HType::TaggedNumber());
1605 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1609 bool can_convert_undefined_to_nan() {
1610 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1613 HType CalculateInferredType() OVERRIDE;
1614 HValue* Canonicalize() OVERRIDE;
1616 Representation from() const { return value()->representation(); }
1617 Representation to() const { return representation(); }
1618 bool deoptimize_on_minus_zero() const {
1619 return CheckFlag(kBailoutOnMinusZero);
1621 Representation RequiredInputRepresentation(int index) OVERRIDE {
1625 Range* InferRange(Zone* zone) OVERRIDE;
1627 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1629 DECLARE_CONCRETE_INSTRUCTION(Change)
1632 bool DataEquals(HValue* other) OVERRIDE { return true; }
1635 bool IsDeletable() const OVERRIDE {
1636 return !from().IsTagged() || value()->type().IsSmi();
1641 class HClampToUint8 FINAL : public HUnaryOperation {
1643 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1645 Representation RequiredInputRepresentation(int index) OVERRIDE {
1646 return Representation::None();
1649 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1652 bool DataEquals(HValue* other) OVERRIDE { return true; }
1655 explicit HClampToUint8(HValue* value)
1656 : HUnaryOperation(value) {
1657 set_representation(Representation::Integer32());
1658 SetFlag(kAllowUndefinedAsNaN);
1662 bool IsDeletable() const OVERRIDE { return true; }
1666 class HDoubleBits FINAL : public HUnaryOperation {
1668 enum Bits { HIGH, LOW };
1669 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1671 Representation RequiredInputRepresentation(int index) OVERRIDE {
1672 return Representation::Double();
1675 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1677 Bits bits() { return bits_; }
1680 bool DataEquals(HValue* other) OVERRIDE {
1681 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1685 HDoubleBits(HValue* value, Bits bits)
1686 : HUnaryOperation(value), bits_(bits) {
1687 set_representation(Representation::Integer32());
1691 bool IsDeletable() const OVERRIDE { return true; }
1697 class HConstructDouble FINAL : public HTemplateInstruction<2> {
1699 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1701 Representation RequiredInputRepresentation(int index) OVERRIDE {
1702 return Representation::Integer32();
1705 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1707 HValue* hi() { return OperandAt(0); }
1708 HValue* lo() { return OperandAt(1); }
1711 bool DataEquals(HValue* other) OVERRIDE { return true; }
1714 explicit HConstructDouble(HValue* hi, HValue* lo) {
1715 set_representation(Representation::Double());
1717 SetOperandAt(0, hi);
1718 SetOperandAt(1, lo);
1721 bool IsDeletable() const OVERRIDE { return true; }
1725 enum RemovableSimulate {
1731 class HSimulate FINAL : public HInstruction {
1733 HSimulate(BailoutId ast_id, int pop_count, Zone* zone,
1734 RemovableSimulate removable)
1736 pop_count_(pop_count),
1738 assigned_indexes_(2, zone),
1740 bit_field_(RemovableField::encode(removable) |
1741 DoneWithReplayField::encode(false)) {}
1744 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1746 bool HasAstId() const { return !ast_id_.IsNone(); }
1747 BailoutId ast_id() const { return ast_id_; }
1748 void set_ast_id(BailoutId id) {
1749 DCHECK(!HasAstId());
1753 int pop_count() const { return pop_count_; }
1754 const ZoneList<HValue*>* values() const { return &values_; }
1755 int GetAssignedIndexAt(int index) const {
1756 DCHECK(HasAssignedIndexAt(index));
1757 return assigned_indexes_[index];
1759 bool HasAssignedIndexAt(int index) const {
1760 return assigned_indexes_[index] != kNoIndex;
1762 void AddAssignedValue(int index, HValue* value) {
1763 AddValue(index, value);
1765 void AddPushedValue(HValue* value) {
1766 AddValue(kNoIndex, value);
1768 int ToOperandIndex(int environment_index) {
1769 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1770 if (assigned_indexes_[i] == environment_index) return i;
1774 int OperandCount() const OVERRIDE { return values_.length(); }
1775 HValue* OperandAt(int index) const OVERRIDE { return values_[index]; }
1777 bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
1778 Representation RequiredInputRepresentation(int index) OVERRIDE {
1779 return Representation::None();
1782 void MergeWith(ZoneList<HSimulate*>* list);
1783 bool is_candidate_for_removal() {
1784 return RemovableField::decode(bit_field_) == REMOVABLE_SIMULATE;
1787 // Replay effects of this instruction on the given environment.
1788 void ReplayEnvironment(HEnvironment* env);
1790 DECLARE_CONCRETE_INSTRUCTION(Simulate)
1793 void Verify() OVERRIDE;
1794 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1795 Handle<JSFunction> closure() const { return closure_; }
1799 void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
1800 values_[index] = value;
1804 static const int kNoIndex = -1;
1805 void AddValue(int index, HValue* value) {
1806 assigned_indexes_.Add(index, zone_);
1807 // Resize the list of pushed values.
1808 values_.Add(NULL, zone_);
1809 // Set the operand through the base method in HValue to make sure that the
1810 // use lists are correctly updated.
1811 SetOperandAt(values_.length() - 1, value);
1813 bool HasValueForIndex(int index) {
1814 for (int i = 0; i < assigned_indexes_.length(); ++i) {
1815 if (assigned_indexes_[i] == index) return true;
1819 bool is_done_with_replay() const {
1820 return DoneWithReplayField::decode(bit_field_);
1822 void set_done_with_replay() {
1823 bit_field_ = DoneWithReplayField::update(bit_field_, true);
1826 class RemovableField : public BitField<RemovableSimulate, 0, 1> {};
1827 class DoneWithReplayField : public BitField<bool, 1, 1> {};
1831 ZoneList<HValue*> values_;
1832 ZoneList<int> assigned_indexes_;
1834 uint32_t bit_field_;
1837 Handle<JSFunction> closure_;
1842 class HEnvironmentMarker FINAL : public HTemplateInstruction<1> {
1844 enum Kind { BIND, LOOKUP };
1846 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1848 Kind kind() const { return kind_; }
1849 int index() const { return index_; }
1850 HSimulate* next_simulate() { return next_simulate_; }
1851 void set_next_simulate(HSimulate* simulate) {
1852 next_simulate_ = simulate;
1855 Representation RequiredInputRepresentation(int index) OVERRIDE {
1856 return Representation::None();
1859 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1862 void set_closure(Handle<JSFunction> closure) {
1863 DCHECK(closure_.is_null());
1864 DCHECK(!closure.is_null());
1867 Handle<JSFunction> closure() const { return closure_; }
1870 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1873 HEnvironmentMarker(Kind kind, int index)
1874 : kind_(kind), index_(index), next_simulate_(NULL) { }
1878 HSimulate* next_simulate_;
1881 Handle<JSFunction> closure_;
1886 class HStackCheck FINAL : public HTemplateInstruction<1> {
1893 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1895 HValue* context() { return OperandAt(0); }
1897 Representation RequiredInputRepresentation(int index) OVERRIDE {
1898 return Representation::Tagged();
1902 // The stack check eliminator might try to eliminate the same stack
1903 // check instruction multiple times.
1905 DeleteAndReplaceWith(NULL);
1909 bool is_function_entry() { return type_ == kFunctionEntry; }
1910 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1912 DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1915 HStackCheck(HValue* context, Type type) : type_(type) {
1916 SetOperandAt(0, context);
1917 SetChangesFlag(kNewSpacePromotion);
1925 NORMAL_RETURN, // Drop the function from the environment on return.
1926 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
1927 GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
1928 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
1932 class HArgumentsObject;
1936 class HEnterInlined FINAL : public HTemplateInstruction<0> {
1938 static HEnterInlined* New(Isolate* isolate, Zone* zone, HValue* context,
1939 BailoutId return_id, Handle<JSFunction> closure,
1940 HConstant* closure_context, int arguments_count,
1941 FunctionLiteral* function,
1942 InliningKind inlining_kind, Variable* arguments_var,
1943 HArgumentsObject* arguments_object) {
1944 return new (zone) HEnterInlined(return_id, closure, closure_context,
1945 arguments_count, function, inlining_kind,
1946 arguments_var, arguments_object, zone);
1949 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
1950 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
1952 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
1954 Handle<JSFunction> closure() const { return closure_; }
1955 HConstant* closure_context() const { return closure_context_; }
1956 int arguments_count() const { return arguments_count_; }
1957 bool arguments_pushed() const { return arguments_pushed_; }
1958 void set_arguments_pushed() { arguments_pushed_ = true; }
1959 FunctionLiteral* function() const { return function_; }
1960 InliningKind inlining_kind() const { return inlining_kind_; }
1961 BailoutId ReturnId() const { return return_id_; }
1962 int inlining_id() const { return inlining_id_; }
1963 void set_inlining_id(int inlining_id) { inlining_id_ = inlining_id; }
1965 Representation RequiredInputRepresentation(int index) OVERRIDE {
1966 return Representation::None();
1969 Variable* arguments_var() { return arguments_var_; }
1970 HArgumentsObject* arguments_object() { return arguments_object_; }
1972 DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
1975 HEnterInlined(BailoutId return_id, Handle<JSFunction> closure,
1976 HConstant* closure_context, int arguments_count,
1977 FunctionLiteral* function, InliningKind inlining_kind,
1978 Variable* arguments_var, HArgumentsObject* arguments_object,
1980 : return_id_(return_id),
1982 closure_context_(closure_context),
1983 arguments_count_(arguments_count),
1984 arguments_pushed_(false),
1985 function_(function),
1986 inlining_kind_(inlining_kind),
1988 arguments_var_(arguments_var),
1989 arguments_object_(arguments_object),
1990 return_targets_(2, zone) {}
1992 BailoutId return_id_;
1993 Handle<JSFunction> closure_;
1994 HConstant* closure_context_;
1995 int arguments_count_;
1996 bool arguments_pushed_;
1997 FunctionLiteral* function_;
1998 InliningKind inlining_kind_;
2000 Variable* arguments_var_;
2001 HArgumentsObject* arguments_object_;
2002 ZoneList<HBasicBlock*> return_targets_;
2006 class HLeaveInlined FINAL : public HTemplateInstruction<0> {
2008 HLeaveInlined(HEnterInlined* entry,
2011 drop_count_(drop_count) { }
2013 Representation RequiredInputRepresentation(int index) OVERRIDE {
2014 return Representation::None();
2017 int argument_delta() const OVERRIDE {
2018 return entry_->arguments_pushed() ? -drop_count_ : 0;
2021 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2024 HEnterInlined* entry_;
2029 class HPushArguments FINAL : public HInstruction {
2031 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context) {
2032 return new(zone) HPushArguments(zone);
2034 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2036 HPushArguments* instr = new(zone) HPushArguments(zone);
2037 instr->AddInput(arg1);
2040 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2041 HValue* arg1, HValue* arg2) {
2042 HPushArguments* instr = new(zone) HPushArguments(zone);
2043 instr->AddInput(arg1);
2044 instr->AddInput(arg2);
2047 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2048 HValue* arg1, HValue* arg2, HValue* arg3) {
2049 HPushArguments* instr = new(zone) HPushArguments(zone);
2050 instr->AddInput(arg1);
2051 instr->AddInput(arg2);
2052 instr->AddInput(arg3);
2055 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context,
2056 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);
2062 instr->AddInput(arg4);
2066 Representation RequiredInputRepresentation(int index) OVERRIDE {
2067 return Representation::Tagged();
2070 int argument_delta() const OVERRIDE { return inputs_.length(); }
2071 HValue* argument(int i) { return OperandAt(i); }
2073 int OperandCount() const FINAL { return inputs_.length(); }
2074 HValue* OperandAt(int i) const FINAL { return inputs_[i]; }
2076 void AddInput(HValue* value);
2078 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2081 void InternalSetOperandAt(int i, HValue* value) FINAL { inputs_[i] = value; }
2084 explicit HPushArguments(Zone* zone)
2085 : HInstruction(HType::Tagged()), inputs_(4, zone) {
2086 set_representation(Representation::Tagged());
2089 ZoneList<HValue*> inputs_;
2093 class HThisFunction FINAL : public HTemplateInstruction<0> {
2095 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2097 Representation RequiredInputRepresentation(int index) OVERRIDE {
2098 return Representation::None();
2101 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2104 bool DataEquals(HValue* other) OVERRIDE { return true; }
2108 set_representation(Representation::Tagged());
2112 bool IsDeletable() const OVERRIDE { return true; }
2116 class HDeclareGlobals FINAL : public HUnaryOperation {
2118 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2122 HValue* context() { return OperandAt(0); }
2123 Handle<FixedArray> pairs() const { return pairs_; }
2124 int flags() const { return flags_; }
2126 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2128 Representation RequiredInputRepresentation(int index) OVERRIDE {
2129 return Representation::Tagged();
2133 HDeclareGlobals(HValue* context,
2134 Handle<FixedArray> pairs,
2136 : HUnaryOperation(context),
2139 set_representation(Representation::Tagged());
2140 SetAllSideEffects();
2143 Handle<FixedArray> pairs_;
2149 class HCall : public HTemplateInstruction<V> {
2151 // The argument count includes the receiver.
2152 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2153 this->set_representation(Representation::Tagged());
2154 this->SetAllSideEffects();
2157 HType CalculateInferredType() FINAL { return HType::Tagged(); }
2159 virtual int argument_count() const {
2160 return argument_count_;
2163 int argument_delta() const OVERRIDE { return -argument_count(); }
2166 int argument_count_;
2170 class HUnaryCall : public HCall<1> {
2172 HUnaryCall(HValue* value, int argument_count)
2173 : HCall<1>(argument_count) {
2174 SetOperandAt(0, value);
2177 Representation RequiredInputRepresentation(int index) FINAL {
2178 return Representation::Tagged();
2181 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2183 HValue* value() const { return OperandAt(0); }
2187 class HBinaryCall : public HCall<2> {
2189 HBinaryCall(HValue* first, HValue* second, int argument_count)
2190 : HCall<2>(argument_count) {
2191 SetOperandAt(0, first);
2192 SetOperandAt(1, second);
2195 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2197 Representation RequiredInputRepresentation(int index) FINAL {
2198 return Representation::Tagged();
2201 HValue* first() const { return OperandAt(0); }
2202 HValue* second() const { return OperandAt(1); }
2206 class HCallJSFunction FINAL : public HCall<1> {
2208 static HCallJSFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2209 HValue* function, int argument_count,
2210 bool pass_argument_count);
2212 HValue* function() const { return OperandAt(0); }
2214 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2216 Representation RequiredInputRepresentation(int index) FINAL {
2218 return Representation::Tagged();
2221 bool pass_argument_count() const { return pass_argument_count_; }
2223 bool HasStackCheck() FINAL { return has_stack_check_; }
2225 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2228 // The argument count includes the receiver.
2229 HCallJSFunction(HValue* function,
2231 bool pass_argument_count,
2232 bool has_stack_check)
2233 : HCall<1>(argument_count),
2234 pass_argument_count_(pass_argument_count),
2235 has_stack_check_(has_stack_check) {
2236 SetOperandAt(0, function);
2239 bool pass_argument_count_;
2240 bool has_stack_check_;
2244 enum CallMode { NORMAL_CALL, TAIL_CALL };
2247 class HCallWithDescriptor FINAL : public HInstruction {
2249 static HCallWithDescriptor* New(Isolate* isolate, Zone* zone, HValue* context,
2250 HValue* target, int argument_count,
2251 CallInterfaceDescriptor descriptor,
2252 const Vector<HValue*>& operands,
2253 CallMode call_mode = NORMAL_CALL) {
2254 DCHECK(operands.length() == descriptor.GetEnvironmentLength());
2255 HCallWithDescriptor* res = new (zone) HCallWithDescriptor(
2256 target, argument_count, descriptor, operands, call_mode, zone);
2260 int OperandCount() const FINAL { return values_.length(); }
2261 HValue* OperandAt(int index) const FINAL { return values_[index]; }
2263 Representation RequiredInputRepresentation(int index) FINAL {
2265 return Representation::Tagged();
2267 int par_index = index - 1;
2268 DCHECK(par_index < descriptor_.GetEnvironmentLength());
2269 return descriptor_.GetParameterRepresentation(par_index);
2273 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2275 HType CalculateInferredType() FINAL { return HType::Tagged(); }
2277 bool IsTailCall() const { return call_mode_ == TAIL_CALL; }
2279 virtual int argument_count() const {
2280 return argument_count_;
2283 int argument_delta() const OVERRIDE { return -argument_count_; }
2285 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2288 return OperandAt(0);
2291 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2294 // The argument count includes the receiver.
2295 HCallWithDescriptor(HValue* target, int argument_count,
2296 CallInterfaceDescriptor descriptor,
2297 const Vector<HValue*>& operands, CallMode call_mode,
2299 : descriptor_(descriptor),
2300 values_(descriptor.GetEnvironmentLength() + 1, zone),
2301 argument_count_(argument_count),
2302 call_mode_(call_mode) {
2303 // We can only tail call without any stack arguments.
2304 DCHECK(call_mode != TAIL_CALL || argument_count == 0);
2305 AddOperand(target, zone);
2306 for (int i = 0; i < operands.length(); i++) {
2307 AddOperand(operands[i], zone);
2309 this->set_representation(Representation::Tagged());
2310 this->SetAllSideEffects();
2313 void AddOperand(HValue* v, Zone* zone) {
2314 values_.Add(NULL, zone);
2315 SetOperandAt(values_.length() - 1, v);
2318 void InternalSetOperandAt(int index, HValue* value) FINAL {
2319 values_[index] = value;
2322 CallInterfaceDescriptor descriptor_;
2323 ZoneList<HValue*> values_;
2324 int argument_count_;
2325 CallMode call_mode_;
2329 class HInvokeFunction FINAL : public HBinaryCall {
2331 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2333 HInvokeFunction(HValue* context,
2335 Handle<JSFunction> known_function,
2337 : HBinaryCall(context, function, argument_count),
2338 known_function_(known_function) {
2339 formal_parameter_count_ =
2340 known_function.is_null()
2342 : known_function->shared()->internal_formal_parameter_count();
2343 has_stack_check_ = !known_function.is_null() &&
2344 (known_function->code()->kind() == Code::FUNCTION ||
2345 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2348 static HInvokeFunction* New(Isolate* isolate, Zone* zone, HValue* context,
2350 Handle<JSFunction> known_function,
2351 int argument_count) {
2352 return new(zone) HInvokeFunction(context, function,
2353 known_function, argument_count);
2356 HValue* context() { return first(); }
2357 HValue* function() { return second(); }
2358 Handle<JSFunction> known_function() { return known_function_; }
2359 int formal_parameter_count() const { return formal_parameter_count_; }
2361 bool HasStackCheck() FINAL { return has_stack_check_; }
2363 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2366 HInvokeFunction(HValue* context, HValue* function, int argument_count)
2367 : HBinaryCall(context, function, argument_count),
2368 has_stack_check_(false) {
2371 Handle<JSFunction> known_function_;
2372 int formal_parameter_count_;
2373 bool has_stack_check_;
2377 class HCallFunction FINAL : public HBinaryCall {
2379 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2380 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2381 HCallFunction, HValue*, int, CallFunctionFlags);
2383 HValue* context() const { return first(); }
2384 HValue* function() const { return second(); }
2385 CallFunctionFlags function_flags() const { return function_flags_; }
2387 FeedbackVectorICSlot slot() const { return slot_; }
2388 Handle<TypeFeedbackVector> feedback_vector() const {
2389 return feedback_vector_;
2391 bool HasVectorAndSlot() const { return !feedback_vector_.is_null(); }
2392 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
2393 FeedbackVectorICSlot slot) {
2394 feedback_vector_ = vector;
2398 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2400 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2402 int argument_delta() const OVERRIDE { return -argument_count(); }
2405 HCallFunction(HValue* context, HValue* function, int argument_count,
2406 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2407 : HBinaryCall(context, function, argument_count),
2408 function_flags_(flags),
2409 slot_(FeedbackVectorICSlot::Invalid()) {}
2410 CallFunctionFlags function_flags_;
2411 Handle<TypeFeedbackVector> feedback_vector_;
2412 FeedbackVectorICSlot slot_;
2416 class HCallNew FINAL : public HBinaryCall {
2418 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2420 HValue* context() { return first(); }
2421 HValue* constructor() { return second(); }
2423 DECLARE_CONCRETE_INSTRUCTION(CallNew)
2426 HCallNew(HValue* context, HValue* constructor, int argument_count)
2427 : HBinaryCall(context, constructor, argument_count) {}
2431 class HCallNewArray FINAL : public HBinaryCall {
2433 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallNewArray,
2438 HValue* context() { return first(); }
2439 HValue* constructor() { return second(); }
2441 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2443 ElementsKind elements_kind() const { return elements_kind_; }
2445 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2448 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2449 ElementsKind elements_kind)
2450 : HBinaryCall(context, constructor, argument_count),
2451 elements_kind_(elements_kind) {}
2453 ElementsKind elements_kind_;
2457 class HCallRuntime FINAL : public HCall<1> {
2459 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime,
2461 const Runtime::Function*,
2464 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2466 HValue* context() { return OperandAt(0); }
2467 const Runtime::Function* function() const { return c_function_; }
2468 Handle<String> name() const { return name_; }
2469 SaveFPRegsMode save_doubles() const { return save_doubles_; }
2470 void set_save_doubles(SaveFPRegsMode save_doubles) {
2471 save_doubles_ = save_doubles;
2474 Representation RequiredInputRepresentation(int index) OVERRIDE {
2475 return Representation::Tagged();
2478 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2481 HCallRuntime(HValue* context,
2482 Handle<String> name,
2483 const Runtime::Function* c_function,
2485 : HCall<1>(argument_count), c_function_(c_function), name_(name),
2486 save_doubles_(kDontSaveFPRegs) {
2487 SetOperandAt(0, context);
2490 const Runtime::Function* c_function_;
2491 Handle<String> name_;
2492 SaveFPRegsMode save_doubles_;
2496 class HMapEnumLength FINAL : public HUnaryOperation {
2498 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2500 Representation RequiredInputRepresentation(int index) OVERRIDE {
2501 return Representation::Tagged();
2504 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2507 bool DataEquals(HValue* other) OVERRIDE { return true; }
2510 explicit HMapEnumLength(HValue* value)
2511 : HUnaryOperation(value, HType::Smi()) {
2512 set_representation(Representation::Smi());
2514 SetDependsOnFlag(kMaps);
2517 bool IsDeletable() const OVERRIDE { return true; }
2521 class HUnaryMathOperation FINAL : public HTemplateInstruction<2> {
2523 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
2524 HValue* value, BuiltinFunctionId op);
2526 HValue* context() const { return OperandAt(0); }
2527 HValue* value() const { return OperandAt(1); }
2529 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2531 Representation RequiredInputRepresentation(int index) OVERRIDE {
2533 return Representation::Tagged();
2543 return Representation::Double();
2545 return representation();
2547 return Representation::Integer32();
2550 return Representation::None();
2555 Range* InferRange(Zone* zone) OVERRIDE;
2557 HValue* Canonicalize() OVERRIDE;
2558 Representation RepresentationFromUses() OVERRIDE;
2559 Representation RepresentationFromInputs() OVERRIDE;
2561 BuiltinFunctionId op() const { return op_; }
2562 const char* OpName() const;
2564 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2567 bool DataEquals(HValue* other) OVERRIDE {
2568 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2569 return op_ == b->op();
2573 // Indicates if we support a double (and int32) output for Math.floor and
2575 bool SupportsFlexibleFloorAndRound() const {
2576 #ifdef V8_TARGET_ARCH_ARM64
2577 // TODO(rmcilroy): Re-enable this for Arm64 once http://crbug.com/476477 is
2584 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2585 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2586 SetOperandAt(0, context);
2587 SetOperandAt(1, value);
2591 if (SupportsFlexibleFloorAndRound()) {
2592 SetFlag(kFlexibleRepresentation);
2594 set_representation(Representation::Integer32());
2598 set_representation(Representation::Integer32());
2601 // Not setting representation here: it is None intentionally.
2602 SetFlag(kFlexibleRepresentation);
2603 // TODO(svenpanne) This flag is actually only needed if representation()
2604 // is tagged, and not when it is an unboxed double or unboxed integer.
2605 SetChangesFlag(kNewSpacePromotion);
2612 set_representation(Representation::Double());
2618 SetFlag(kAllowUndefinedAsNaN);
2621 bool IsDeletable() const OVERRIDE { return true; }
2623 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2624 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2626 BuiltinFunctionId op_;
2630 class HLoadRoot FINAL : public HTemplateInstruction<0> {
2632 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2633 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2635 Representation RequiredInputRepresentation(int index) OVERRIDE {
2636 return Representation::None();
2639 Heap::RootListIndex index() const { return index_; }
2641 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2644 bool DataEquals(HValue* other) OVERRIDE {
2645 HLoadRoot* b = HLoadRoot::cast(other);
2646 return index_ == b->index_;
2650 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2651 : HTemplateInstruction<0>(type), index_(index) {
2653 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2654 // corresponding HStoreRoot instruction.
2655 SetDependsOnFlag(kCalls);
2656 set_representation(Representation::Tagged());
2659 bool IsDeletable() const OVERRIDE { return true; }
2661 const Heap::RootListIndex index_;
2665 class HCheckMaps FINAL : public HTemplateInstruction<2> {
2667 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2668 HValue* value, Handle<Map> map,
2669 HValue* typecheck = NULL) {
2670 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2671 Unique<Map>::CreateImmovable(map), zone), typecheck);
2673 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2674 HValue* value, SmallMapList* map_list,
2675 HValue* typecheck = NULL) {
2676 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2677 for (int i = 0; i < map_list->length(); ++i) {
2678 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2680 return new(zone) HCheckMaps(value, maps, typecheck);
2683 bool IsStabilityCheck() const {
2684 return IsStabilityCheckField::decode(bit_field_);
2686 void MarkAsStabilityCheck() {
2687 bit_field_ = MapsAreStableField::encode(true) |
2688 HasMigrationTargetField::encode(false) |
2689 IsStabilityCheckField::encode(true);
2690 ClearChangesFlag(kNewSpacePromotion);
2691 ClearDependsOnFlag(kElementsKind);
2692 ClearDependsOnFlag(kMaps);
2695 bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
2696 Representation RequiredInputRepresentation(int index) OVERRIDE {
2697 return Representation::Tagged();
2700 HType CalculateInferredType() OVERRIDE {
2701 if (value()->type().IsHeapObject()) return value()->type();
2702 return HType::HeapObject();
2705 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2707 HValue* value() const { return OperandAt(0); }
2708 HValue* typecheck() const { return OperandAt(1); }
2710 const UniqueSet<Map>* maps() const { return maps_; }
2711 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2713 bool maps_are_stable() const {
2714 return MapsAreStableField::decode(bit_field_);
2717 bool HasMigrationTarget() const {
2718 return HasMigrationTargetField::decode(bit_field_);
2721 HValue* Canonicalize() OVERRIDE;
2723 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2727 HInstruction* instr) {
2728 return instr->Append(new(zone) HCheckMaps(
2729 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2732 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2734 const UniqueSet<Map>* maps,
2735 bool maps_are_stable,
2736 HInstruction* instr) {
2737 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2740 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2743 bool DataEquals(HValue* other) OVERRIDE {
2744 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2747 int RedefinedOperandIndex() OVERRIDE { return 0; }
2750 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2751 : HTemplateInstruction<2>(HType::HeapObject()),
2753 bit_field_(HasMigrationTargetField::encode(false) |
2754 IsStabilityCheckField::encode(false) |
2755 MapsAreStableField::encode(maps_are_stable)) {
2756 DCHECK_NE(0, maps->size());
2757 SetOperandAt(0, value);
2758 // Use the object value for the dependency.
2759 SetOperandAt(1, value);
2760 set_representation(Representation::Tagged());
2762 SetDependsOnFlag(kMaps);
2763 SetDependsOnFlag(kElementsKind);
2766 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2767 : HTemplateInstruction<2>(HType::HeapObject()),
2769 bit_field_(HasMigrationTargetField::encode(false) |
2770 IsStabilityCheckField::encode(false) |
2771 MapsAreStableField::encode(true)) {
2772 DCHECK_NE(0, maps->size());
2773 SetOperandAt(0, value);
2774 // Use the object value for the dependency if NULL is passed.
2775 SetOperandAt(1, typecheck ? typecheck : value);
2776 set_representation(Representation::Tagged());
2778 SetDependsOnFlag(kMaps);
2779 SetDependsOnFlag(kElementsKind);
2780 for (int i = 0; i < maps->size(); ++i) {
2781 Handle<Map> map = maps->at(i).handle();
2782 if (map->is_migration_target()) {
2783 bit_field_ = HasMigrationTargetField::update(bit_field_, true);
2785 if (!map->is_stable()) {
2786 bit_field_ = MapsAreStableField::update(bit_field_, false);
2789 if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion);
2792 class HasMigrationTargetField : public BitField<bool, 0, 1> {};
2793 class IsStabilityCheckField : public BitField<bool, 1, 1> {};
2794 class MapsAreStableField : public BitField<bool, 2, 1> {};
2796 const UniqueSet<Map>* maps_;
2797 uint32_t bit_field_;
2801 class HCheckValue FINAL : public HUnaryOperation {
2803 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2804 HValue* value, Handle<JSFunction> func) {
2805 bool in_new_space = isolate->heap()->InNewSpace(*func);
2806 // NOTE: We create an uninitialized Unique and initialize it later.
2807 // This is because a JSFunction can move due to GC during graph creation.
2808 // TODO(titzer): This is a migration crutch. Replace with some kind of
2809 // Uniqueness scope later.
2810 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2811 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2814 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2815 HValue* value, Unique<HeapObject> target,
2816 bool object_in_new_space) {
2817 return new(zone) HCheckValue(value, target, object_in_new_space);
2820 void FinalizeUniqueness() OVERRIDE {
2821 object_ = Unique<HeapObject>(object_.handle());
2824 Representation RequiredInputRepresentation(int index) OVERRIDE {
2825 return Representation::Tagged();
2827 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2829 HValue* Canonicalize() OVERRIDE;
2832 void Verify() OVERRIDE;
2835 Unique<HeapObject> object() const { return object_; }
2836 bool object_in_new_space() const { return object_in_new_space_; }
2838 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2841 bool DataEquals(HValue* other) OVERRIDE {
2842 HCheckValue* b = HCheckValue::cast(other);
2843 return object_ == b->object_;
2847 HCheckValue(HValue* value, Unique<HeapObject> object,
2848 bool object_in_new_space)
2849 : HUnaryOperation(value, value->type()),
2851 object_in_new_space_(object_in_new_space) {
2852 set_representation(Representation::Tagged());
2856 Unique<HeapObject> object_;
2857 bool object_in_new_space_;
2861 class HCheckInstanceType FINAL : public HUnaryOperation {
2867 IS_INTERNALIZED_STRING,
2868 LAST_INTERVAL_CHECK = IS_JS_ARRAY
2871 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2873 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
2875 Representation RequiredInputRepresentation(int index) OVERRIDE {
2876 return Representation::Tagged();
2879 HType CalculateInferredType() OVERRIDE {
2881 case IS_SPEC_OBJECT: return HType::JSObject();
2882 case IS_JS_ARRAY: return HType::JSArray();
2883 case IS_STRING: return HType::String();
2884 case IS_INTERNALIZED_STRING: return HType::String();
2887 return HType::Tagged();
2890 HValue* Canonicalize() OVERRIDE;
2892 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2893 void GetCheckInterval(InstanceType* first, InstanceType* last);
2894 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2896 Check check() const { return check_; }
2898 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2901 // TODO(ager): It could be nice to allow the ommision of instance
2902 // type checks if we have already performed an instance type check
2903 // with a larger range.
2904 bool DataEquals(HValue* other) OVERRIDE {
2905 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2906 return check_ == b->check_;
2909 int RedefinedOperandIndex() OVERRIDE { return 0; }
2912 const char* GetCheckName() const;
2914 HCheckInstanceType(HValue* value, Check check)
2915 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2916 set_representation(Representation::Tagged());
2924 class HCheckSmi FINAL : public HUnaryOperation {
2926 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2928 Representation RequiredInputRepresentation(int index) OVERRIDE {
2929 return Representation::Tagged();
2932 HValue* Canonicalize() OVERRIDE {
2933 HType value_type = value()->type();
2934 if (value_type.IsSmi()) {
2940 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
2943 bool DataEquals(HValue* other) OVERRIDE { return true; }
2946 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
2947 set_representation(Representation::Smi());
2953 class HCheckHeapObject FINAL : public HUnaryOperation {
2955 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
2957 bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
2958 Representation RequiredInputRepresentation(int index) OVERRIDE {
2959 return Representation::Tagged();
2962 HType CalculateInferredType() OVERRIDE {
2963 if (value()->type().IsHeapObject()) return value()->type();
2964 return HType::HeapObject();
2968 void Verify() OVERRIDE;
2971 HValue* Canonicalize() OVERRIDE {
2972 return value()->type().IsHeapObject() ? NULL : this;
2975 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
2978 bool DataEquals(HValue* other) OVERRIDE { return true; }
2981 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
2982 set_representation(Representation::Tagged());
2988 class InductionVariableData;
2991 struct InductionVariableLimitUpdate {
2992 InductionVariableData* updated_variable;
2994 bool limit_is_upper;
2995 bool limit_is_included;
2997 InductionVariableLimitUpdate()
2998 : updated_variable(NULL), limit(NULL),
2999 limit_is_upper(false), limit_is_included(false) {}
3008 class InductionVariableData FINAL : public ZoneObject {
3010 class InductionVariableCheck : public ZoneObject {
3012 HBoundsCheck* check() { return check_; }
3013 InductionVariableCheck* next() { return next_; }
3014 bool HasUpperLimit() { return upper_limit_ >= 0; }
3015 int32_t upper_limit() {
3016 DCHECK(HasUpperLimit());
3017 return upper_limit_;
3019 void set_upper_limit(int32_t upper_limit) {
3020 upper_limit_ = upper_limit;
3023 bool processed() { return processed_; }
3024 void set_processed() { processed_ = true; }
3026 InductionVariableCheck(HBoundsCheck* check,
3027 InductionVariableCheck* next,
3028 int32_t upper_limit = kNoLimit)
3029 : check_(check), next_(next), upper_limit_(upper_limit),
3030 processed_(false) {}
3033 HBoundsCheck* check_;
3034 InductionVariableCheck* next_;
3035 int32_t upper_limit_;
3039 class ChecksRelatedToLength : public ZoneObject {
3041 HValue* length() { return length_; }
3042 ChecksRelatedToLength* next() { return next_; }
3043 InductionVariableCheck* checks() { return checks_; }
3045 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3046 void CloseCurrentBlock();
3048 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3049 : length_(length), next_(next), checks_(NULL),
3050 first_check_in_block_(NULL),
3052 added_constant_(NULL),
3053 current_and_mask_in_block_(0),
3054 current_or_mask_in_block_(0) {}
3057 void UseNewIndexInCurrentBlock(Token::Value token,
3062 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3063 HBitwise* added_index() { return added_index_; }
3064 void set_added_index(HBitwise* index) { added_index_ = index; }
3065 HConstant* added_constant() { return added_constant_; }
3066 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3067 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3068 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3069 int32_t current_upper_limit() { return current_upper_limit_; }
3072 ChecksRelatedToLength* next_;
3073 InductionVariableCheck* checks_;
3075 HBoundsCheck* first_check_in_block_;
3076 HBitwise* added_index_;
3077 HConstant* added_constant_;
3078 int32_t current_and_mask_in_block_;
3079 int32_t current_or_mask_in_block_;
3080 int32_t current_upper_limit_;
3083 struct LimitFromPredecessorBlock {
3084 InductionVariableData* variable;
3087 HBasicBlock* other_target;
3089 bool LimitIsValid() { return token != Token::ILLEGAL; }
3091 bool LimitIsIncluded() {
3092 return Token::IsEqualityOp(token) ||
3093 token == Token::GTE || token == Token::LTE;
3095 bool LimitIsUpper() {
3096 return token == Token::LTE || token == Token::LT || token == Token::NE;
3099 LimitFromPredecessorBlock()
3101 token(Token::ILLEGAL),
3103 other_target(NULL) {}
3106 static const int32_t kNoLimit = -1;
3108 static InductionVariableData* ExaminePhi(HPhi* phi);
3109 static void ComputeLimitFromPredecessorBlock(
3111 LimitFromPredecessorBlock* result);
3112 static bool ComputeInductionVariableLimit(
3114 InductionVariableLimitUpdate* additional_limit);
3116 struct BitwiseDecompositionResult {
3122 BitwiseDecompositionResult()
3123 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3125 static void DecomposeBitwise(HValue* value,
3126 BitwiseDecompositionResult* result);
3128 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3130 bool CheckIfBranchIsLoopGuard(Token::Value token,
3131 HBasicBlock* current_branch,
3132 HBasicBlock* other_branch);
3134 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3136 HPhi* phi() { return phi_; }
3137 HValue* base() { return base_; }
3138 int32_t increment() { return increment_; }
3139 HValue* limit() { return limit_; }
3140 bool limit_included() { return limit_included_; }
3141 HBasicBlock* limit_validity() { return limit_validity_; }
3142 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3143 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3144 ChecksRelatedToLength* checks() { return checks_; }
3145 HValue* additional_upper_limit() { return additional_upper_limit_; }
3146 bool additional_upper_limit_is_included() {
3147 return additional_upper_limit_is_included_;
3149 HValue* additional_lower_limit() { return additional_lower_limit_; }
3150 bool additional_lower_limit_is_included() {
3151 return additional_lower_limit_is_included_;
3154 bool LowerLimitIsNonNegativeConstant() {
3155 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3158 if (additional_lower_limit() != NULL &&
3159 additional_lower_limit()->IsInteger32Constant() &&
3160 additional_lower_limit()->GetInteger32Constant() >= 0) {
3161 // Ignoring the corner case of !additional_lower_limit_is_included()
3162 // is safe, handling it adds unneeded complexity.
3168 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3171 template <class T> void swap(T* a, T* b) {
3177 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3178 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3179 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3180 induction_exit_block_(NULL), induction_exit_target_(NULL),
3182 additional_upper_limit_(NULL),
3183 additional_upper_limit_is_included_(false),
3184 additional_lower_limit_(NULL),
3185 additional_lower_limit_is_included_(false) {}
3187 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3189 static HValue* IgnoreOsrValue(HValue* v);
3190 static InductionVariableData* GetInductionVariableData(HValue* v);
3196 bool limit_included_;
3197 HBasicBlock* limit_validity_;
3198 HBasicBlock* induction_exit_block_;
3199 HBasicBlock* induction_exit_target_;
3200 ChecksRelatedToLength* checks_;
3201 HValue* additional_upper_limit_;
3202 bool additional_upper_limit_is_included_;
3203 HValue* additional_lower_limit_;
3204 bool additional_lower_limit_is_included_;
3208 class HPhi FINAL : public HValue {
3210 HPhi(int merged_index, Zone* zone)
3212 merged_index_(merged_index),
3214 induction_variable_data_(NULL) {
3215 for (int i = 0; i < Representation::kNumRepresentations; i++) {
3216 non_phi_uses_[i] = 0;
3217 indirect_uses_[i] = 0;
3219 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3220 SetFlag(kFlexibleRepresentation);
3221 SetFlag(kAllowUndefinedAsNaN);
3224 Representation RepresentationFromInputs() OVERRIDE;
3226 Range* InferRange(Zone* zone) OVERRIDE;
3227 virtual void InferRepresentation(
3228 HInferRepresentationPhase* h_infer) OVERRIDE;
3229 Representation RequiredInputRepresentation(int index) OVERRIDE {
3230 return representation();
3232 Representation KnownOptimalRepresentation() OVERRIDE {
3233 return representation();
3235 HType CalculateInferredType() OVERRIDE;
3236 int OperandCount() const OVERRIDE { return inputs_.length(); }
3237 HValue* OperandAt(int index) const OVERRIDE { return inputs_[index]; }
3238 HValue* GetRedundantReplacement();
3239 void AddInput(HValue* value);
3242 bool IsReceiver() const { return merged_index_ == 0; }
3243 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3245 SourcePosition position() const OVERRIDE;
3247 int merged_index() const { return merged_index_; }
3249 InductionVariableData* induction_variable_data() {
3250 return induction_variable_data_;
3252 bool IsInductionVariable() {
3253 return induction_variable_data_ != NULL;
3255 bool IsLimitedInductionVariable() {
3256 return IsInductionVariable() &&
3257 induction_variable_data_->limit() != NULL;
3259 void DetectInductionVariable() {
3260 DCHECK(induction_variable_data_ == NULL);
3261 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3264 std::ostream& PrintTo(std::ostream& os) const OVERRIDE; // NOLINT
3267 void Verify() OVERRIDE;
3270 void InitRealUses(int id);
3271 void AddNonPhiUsesFrom(HPhi* other);
3272 void AddIndirectUsesTo(int* use_count);
3274 int tagged_non_phi_uses() const {
3275 return non_phi_uses_[Representation::kTagged];
3277 int smi_non_phi_uses() const {
3278 return non_phi_uses_[Representation::kSmi];
3280 int int32_non_phi_uses() const {
3281 return non_phi_uses_[Representation::kInteger32];
3283 int double_non_phi_uses() const {
3284 return non_phi_uses_[Representation::kDouble];
3286 int tagged_indirect_uses() const {
3287 return indirect_uses_[Representation::kTagged];
3289 int smi_indirect_uses() const {
3290 return indirect_uses_[Representation::kSmi];
3292 int int32_indirect_uses() const {
3293 return indirect_uses_[Representation::kInteger32];
3295 int double_indirect_uses() const {
3296 return indirect_uses_[Representation::kDouble];
3298 int phi_id() { return phi_id_; }
3300 static HPhi* cast(HValue* value) {
3301 DCHECK(value->IsPhi());
3302 return reinterpret_cast<HPhi*>(value);
3304 Opcode opcode() const OVERRIDE { return HValue::kPhi; }
3306 void SimplifyConstantInputs();
3308 // Marker value representing an invalid merge index.
3309 static const int kInvalidMergedIndex = -1;
3312 void DeleteFromGraph() OVERRIDE;
3313 void InternalSetOperandAt(int index, HValue* value) OVERRIDE {
3314 inputs_[index] = value;
3318 ZoneList<HValue*> inputs_;
3321 int non_phi_uses_[Representation::kNumRepresentations];
3322 int indirect_uses_[Representation::kNumRepresentations];
3324 InductionVariableData* induction_variable_data_;
3326 // TODO(titzer): we can't eliminate the receiver for generating backtraces
3327 bool IsDeletable() const OVERRIDE { return !IsReceiver(); }
3331 // Common base class for HArgumentsObject and HCapturedObject.
3332 class HDematerializedObject : public HInstruction {
3334 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3336 int OperandCount() const FINAL { return values_.length(); }
3337 HValue* OperandAt(int index) const FINAL { return values_[index]; }
3339 bool HasEscapingOperandAt(int index) FINAL { return false; }
3340 Representation RequiredInputRepresentation(int index) FINAL {
3341 return Representation::None();
3345 void InternalSetOperandAt(int index, HValue* value) FINAL {
3346 values_[index] = value;
3349 // List of values tracked by this marker.
3350 ZoneList<HValue*> values_;
3354 class HArgumentsObject FINAL : public HDematerializedObject {
3356 static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context,
3358 return new(zone) HArgumentsObject(count, zone);
3361 // The values contain a list of all elements in the arguments object
3362 // including the receiver object, which is skipped when materializing.
3363 const ZoneList<HValue*>* arguments_values() const { return &values_; }
3364 int arguments_count() const { return values_.length(); }
3366 void AddArgument(HValue* argument, Zone* zone) {
3367 values_.Add(NULL, zone); // Resize list.
3368 SetOperandAt(values_.length() - 1, argument);
3371 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3374 HArgumentsObject(int count, Zone* zone)
3375 : HDematerializedObject(count, zone) {
3376 set_representation(Representation::Tagged());
3377 SetFlag(kIsArguments);
3382 class HCapturedObject FINAL : public HDematerializedObject {
3384 HCapturedObject(int length, int id, Zone* zone)
3385 : HDematerializedObject(length, zone), capture_id_(id) {
3386 set_representation(Representation::Tagged());
3387 values_.AddBlock(NULL, length, zone); // Resize list.
3390 // The values contain a list of all in-object properties inside the
3391 // captured object and is index by field index. Properties in the
3392 // properties or elements backing store are not tracked here.
3393 const ZoneList<HValue*>* values() const { return &values_; }
3394 int length() const { return values_.length(); }
3395 int capture_id() const { return capture_id_; }
3397 // Shortcut for the map value of this captured object.
3398 HValue* map_value() const { return values()->first(); }
3400 void ReuseSideEffectsFromStore(HInstruction* store) {
3401 DCHECK(store->HasObservableSideEffects());
3402 DCHECK(store->IsStoreNamedField());
3403 changes_flags_.Add(store->ChangesFlags());
3406 // Replay effects of this instruction on the given environment.
3407 void ReplayEnvironment(HEnvironment* env);
3409 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3411 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3416 // Note that we cannot DCE captured objects as they are used to replay
3417 // the environment. This method is here as an explicit reminder.
3418 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3419 bool IsDeletable() const FINAL { return false; }
3423 class HConstant FINAL : public HTemplateInstruction<0> {
3425 enum Special { kHoleNaN };
3427 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special);
3428 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3429 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3430 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3431 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3432 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3434 static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone,
3435 HValue* context, int32_t value,
3436 Representation representation,
3437 HInstruction* instruction) {
3438 return instruction->Append(
3439 HConstant::New(isolate, zone, context, value, representation));
3442 Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
3443 Handle<Object> object = object_.handle();
3444 if (!object.is_null() && object->IsHeapObject()) {
3445 return v8::internal::handle(HeapObject::cast(*object)->map());
3447 return Handle<Map>();
3450 static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone,
3451 HValue* context, int32_t value,
3452 Representation representation,
3453 HInstruction* instruction) {
3454 return instruction->Prepend(
3455 HConstant::New(isolate, zone, context, value, representation));
3458 static HConstant* CreateAndInsertBefore(Zone* zone,
3461 HInstruction* instruction) {
3462 return instruction->Prepend(new(zone) HConstant(
3463 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3464 Representation::Tagged(), HType::HeapObject(), true,
3465 false, false, MAP_TYPE));
3468 static HConstant* CreateAndInsertAfter(Zone* zone,
3471 HInstruction* instruction) {
3472 return instruction->Append(new(zone) HConstant(
3473 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3474 Representation::Tagged(), HType::HeapObject(), true,
3475 false, false, MAP_TYPE));
3478 Handle<Object> handle(Isolate* isolate) {
3479 if (object_.handle().is_null()) {
3480 // Default arguments to is_not_in_new_space depend on this heap number
3481 // to be tenured so that it's guaranteed not to be located in new space.
3482 object_ = Unique<Object>::CreateUninitialized(
3483 isolate->factory()->NewNumber(double_value_, TENURED));
3485 AllowDeferredHandleDereference smi_check;
3486 DCHECK(HasInteger32Value() || !object_.handle()->IsSmi());
3487 return object_.handle();
3490 bool IsSpecialDouble() const {
3491 return HasDoubleValue() &&
3492 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3493 std::isnan(double_value_));
3496 bool NotInNewSpace() const {
3497 return IsNotInNewSpaceField::decode(bit_field_);
3500 bool ImmortalImmovable() const;
3502 bool IsCell() const {
3503 InstanceType instance_type = GetInstanceType();
3504 return instance_type == CELL_TYPE;
3507 Representation RequiredInputRepresentation(int index) OVERRIDE {
3508 return Representation::None();
3511 Representation KnownOptimalRepresentation() OVERRIDE {
3512 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3513 if (HasInteger32Value()) return Representation::Integer32();
3514 if (HasNumberValue()) return Representation::Double();
3515 if (HasExternalReferenceValue()) return Representation::External();
3516 return Representation::Tagged();
3519 bool EmitAtUses() OVERRIDE;
3520 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3521 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3522 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3523 Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone);
3524 bool HasInteger32Value() const {
3525 return HasInt32ValueField::decode(bit_field_);
3527 int32_t Integer32Value() const {
3528 DCHECK(HasInteger32Value());
3529 return int32_value_;
3531 bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); }
3532 bool HasDoubleValue() const {
3533 return HasDoubleValueField::decode(bit_field_);
3535 double DoubleValue() const {
3536 DCHECK(HasDoubleValue());
3537 return double_value_;
3539 uint64_t DoubleValueAsBits() const {
3541 DCHECK(HasDoubleValue());
3542 STATIC_ASSERT(sizeof(bits) == sizeof(double_value_));
3543 std::memcpy(&bits, &double_value_, sizeof(bits));
3546 bool IsTheHole() const {
3547 if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) {
3550 return object_.IsInitialized() &&
3551 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3553 bool HasNumberValue() const { return HasDoubleValue(); }
3554 int32_t NumberValueAsInteger32() const {
3555 DCHECK(HasNumberValue());
3556 // Irrespective of whether a numeric HConstant can be safely
3557 // represented as an int32, we store the (in some cases lossy)
3558 // representation of the number in int32_value_.
3559 return int32_value_;
3561 bool HasStringValue() const {
3562 if (HasNumberValue()) return false;
3563 DCHECK(!object_.handle().is_null());
3564 return GetInstanceType() < FIRST_NONSTRING_TYPE;
3566 Handle<String> StringValue() const {
3567 DCHECK(HasStringValue());
3568 return Handle<String>::cast(object_.handle());
3570 bool HasInternalizedStringValue() const {
3571 return HasStringValue() && StringShape(GetInstanceType()).IsInternalized();
3574 bool HasExternalReferenceValue() const {
3575 return HasExternalReferenceValueField::decode(bit_field_);
3577 ExternalReference ExternalReferenceValue() const {
3578 return external_reference_value_;
3581 bool HasBooleanValue() const { return type_.IsBoolean(); }
3582 bool BooleanValue() const { return BooleanValueField::decode(bit_field_); }
3583 bool IsUndetectable() const {
3584 return IsUndetectableField::decode(bit_field_);
3586 InstanceType GetInstanceType() const {
3587 return InstanceTypeField::decode(bit_field_);
3590 bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; }
3591 Unique<Map> MapValue() const {
3592 DCHECK(HasMapValue());
3593 return Unique<Map>::cast(GetUnique());
3595 bool HasStableMapValue() const {
3596 DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_));
3597 return HasStableMapValueField::decode(bit_field_);
3600 bool HasObjectMap() const { return !object_map_.IsNull(); }
3601 Unique<Map> ObjectMap() const {
3602 DCHECK(HasObjectMap());
3606 intptr_t Hashcode() OVERRIDE {
3607 if (HasInteger32Value()) {
3608 return static_cast<intptr_t>(int32_value_);
3609 } else if (HasDoubleValue()) {
3610 uint64_t bits = DoubleValueAsBits();
3611 if (sizeof(bits) > sizeof(intptr_t)) {
3612 bits ^= (bits >> 32);
3614 return static_cast<intptr_t>(bits);
3615 } else if (HasExternalReferenceValue()) {
3616 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3618 DCHECK(!object_.handle().is_null());
3619 return object_.Hashcode();
3623 void FinalizeUniqueness() OVERRIDE {
3624 if (!HasDoubleValue() && !HasExternalReferenceValue()) {
3625 DCHECK(!object_.handle().is_null());
3626 object_ = Unique<Object>(object_.handle());
3630 Unique<Object> GetUnique() const {
3634 bool EqualsUnique(Unique<Object> other) const {
3635 return object_.IsInitialized() && object_ == other;
3638 bool DataEquals(HValue* other) OVERRIDE {
3639 HConstant* other_constant = HConstant::cast(other);
3640 if (HasInteger32Value()) {
3641 return other_constant->HasInteger32Value() &&
3642 int32_value_ == other_constant->int32_value_;
3643 } else if (HasDoubleValue()) {
3644 return other_constant->HasDoubleValue() &&
3645 std::memcmp(&double_value_, &other_constant->double_value_,
3646 sizeof(double_value_)) == 0;
3647 } else if (HasExternalReferenceValue()) {
3648 return other_constant->HasExternalReferenceValue() &&
3649 external_reference_value_ ==
3650 other_constant->external_reference_value_;
3652 if (other_constant->HasInteger32Value() ||
3653 other_constant->HasDoubleValue() ||
3654 other_constant->HasExternalReferenceValue()) {
3657 DCHECK(!object_.handle().is_null());
3658 return other_constant->object_ == object_;
3663 void Verify() OVERRIDE {}
3666 DECLARE_CONCRETE_INSTRUCTION(Constant)
3669 Range* InferRange(Zone* zone) OVERRIDE;
3672 friend class HGraph;
3673 explicit HConstant(Special special);
3674 explicit HConstant(Handle<Object> handle,
3675 Representation r = Representation::None());
3676 HConstant(int32_t value,
3677 Representation r = Representation::None(),
3678 bool is_not_in_new_space = true,
3679 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3680 HConstant(double value,
3681 Representation r = Representation::None(),
3682 bool is_not_in_new_space = true,
3683 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3684 HConstant(Unique<Object> object,
3685 Unique<Map> object_map,
3686 bool has_stable_map_value,
3689 bool is_not_in_new_space,
3691 bool is_undetectable,
3692 InstanceType instance_type);
3694 explicit HConstant(ExternalReference reference);
3696 void Initialize(Representation r);
3698 bool IsDeletable() const OVERRIDE { return true; }
3700 // If object_ is a map, this indicates whether the map is stable.
3701 class HasStableMapValueField : public BitField<bool, 0, 1> {};
3703 // We store the HConstant in the most specific form safely possible.
3704 // These flags tell us if the respective member fields hold valid, safe
3705 // representations of the constant. More specific flags imply more general
3706 // flags, but not the converse (i.e. smi => int32 => double).
3707 class HasSmiValueField : public BitField<bool, 1, 1> {};
3708 class HasInt32ValueField : public BitField<bool, 2, 1> {};
3709 class HasDoubleValueField : public BitField<bool, 3, 1> {};
3711 class HasExternalReferenceValueField : public BitField<bool, 4, 1> {};
3712 class IsNotInNewSpaceField : public BitField<bool, 5, 1> {};
3713 class BooleanValueField : public BitField<bool, 6, 1> {};
3714 class IsUndetectableField : public BitField<bool, 7, 1> {};
3716 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3717 class InstanceTypeField : public BitField<InstanceType, 8, 8> {};
3719 // If this is a numerical constant, object_ either points to the
3720 // HeapObject the constant originated from or is null. If the
3721 // constant is non-numeric, object_ always points to a valid
3722 // constant HeapObject.
3723 Unique<Object> object_;
3725 // If object_ is a heap object, this points to the stable map of the object.
3726 Unique<Map> object_map_;
3728 uint32_t bit_field_;
3730 int32_t int32_value_;
3731 double double_value_;
3732 ExternalReference external_reference_value_;
3736 class HBinaryOperation : public HTemplateInstruction<3> {
3738 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3739 HType type = HType::Tagged())
3740 : HTemplateInstruction<3>(type),
3741 observed_output_representation_(Representation::None()) {
3742 DCHECK(left != NULL && right != NULL);
3743 SetOperandAt(0, context);
3744 SetOperandAt(1, left);
3745 SetOperandAt(2, right);
3746 observed_input_representation_[0] = Representation::None();
3747 observed_input_representation_[1] = Representation::None();
3750 HValue* context() const { return OperandAt(0); }
3751 HValue* left() const { return OperandAt(1); }
3752 HValue* right() const { return OperandAt(2); }
3754 // True if switching left and right operands likely generates better code.
3755 bool AreOperandsBetterSwitched() {
3756 if (!IsCommutative()) return false;
3758 // Constant operands are better off on the right, they can be inlined in
3759 // many situations on most platforms.
3760 if (left()->IsConstant()) return true;
3761 if (right()->IsConstant()) return false;
3763 // Otherwise, if there is only one use of the right operand, it would be
3764 // better off on the left for platforms that only have 2-arg arithmetic
3765 // ops (e.g ia32, x64) that clobber the left operand.
3766 return right()->HasOneUse();
3769 HValue* BetterLeftOperand() {
3770 return AreOperandsBetterSwitched() ? right() : left();
3773 HValue* BetterRightOperand() {
3774 return AreOperandsBetterSwitched() ? left() : right();
3777 void set_observed_input_representation(int index, Representation rep) {
3778 DCHECK(index >= 1 && index <= 2);
3779 observed_input_representation_[index - 1] = rep;
3782 virtual void initialize_output_representation(Representation observed) {
3783 observed_output_representation_ = observed;
3786 Representation observed_input_representation(int index) OVERRIDE {
3787 if (index == 0) return Representation::Tagged();
3788 return observed_input_representation_[index - 1];
3791 virtual void UpdateRepresentation(Representation new_rep,
3792 HInferRepresentationPhase* h_infer,
3793 const char* reason) OVERRIDE {
3794 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3795 ? Representation::Integer32() : new_rep;
3796 HValue::UpdateRepresentation(rep, h_infer, reason);
3799 virtual void InferRepresentation(
3800 HInferRepresentationPhase* h_infer) OVERRIDE;
3801 Representation RepresentationFromInputs() OVERRIDE;
3802 Representation RepresentationFromOutput();
3803 void AssumeRepresentation(Representation r) OVERRIDE;
3805 virtual bool IsCommutative() const { return false; }
3807 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3809 Representation RequiredInputRepresentation(int index) OVERRIDE {
3810 if (index == 0) return Representation::Tagged();
3811 return representation();
3814 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
3815 SourcePosition right_pos) {
3816 set_operand_position(zone, 1, left_pos);
3817 set_operand_position(zone, 2, right_pos);
3820 bool RightIsPowerOf2() {
3821 if (!right()->IsInteger32Constant()) return false;
3822 int32_t value = right()->GetInteger32Constant();
3824 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3826 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3829 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3832 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3834 Representation observed_input_representation_[2];
3835 Representation observed_output_representation_;
3839 class HWrapReceiver FINAL : public HTemplateInstruction<2> {
3841 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3843 bool DataEquals(HValue* other) OVERRIDE { return true; }
3845 Representation RequiredInputRepresentation(int index) OVERRIDE {
3846 return Representation::Tagged();
3849 HValue* receiver() const { return OperandAt(0); }
3850 HValue* function() const { return OperandAt(1); }
3852 HValue* Canonicalize() OVERRIDE;
3854 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3855 bool known_function() const { return known_function_; }
3857 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3860 HWrapReceiver(HValue* receiver, HValue* function) {
3861 known_function_ = function->IsConstant() &&
3862 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3863 set_representation(Representation::Tagged());
3864 SetOperandAt(0, receiver);
3865 SetOperandAt(1, function);
3869 bool known_function_;
3873 class HApplyArguments FINAL : public HTemplateInstruction<4> {
3875 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3878 Representation RequiredInputRepresentation(int index) OVERRIDE {
3879 // The length is untagged, all other inputs are tagged.
3881 ? Representation::Integer32()
3882 : Representation::Tagged();
3885 HValue* function() { return OperandAt(0); }
3886 HValue* receiver() { return OperandAt(1); }
3887 HValue* length() { return OperandAt(2); }
3888 HValue* elements() { return OperandAt(3); }
3890 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3893 HApplyArguments(HValue* function,
3897 set_representation(Representation::Tagged());
3898 SetOperandAt(0, function);
3899 SetOperandAt(1, receiver);
3900 SetOperandAt(2, length);
3901 SetOperandAt(3, elements);
3902 SetAllSideEffects();
3907 class HArgumentsElements FINAL : public HTemplateInstruction<0> {
3909 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3911 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3913 Representation RequiredInputRepresentation(int index) OVERRIDE {
3914 return Representation::None();
3917 bool from_inlined() const { return from_inlined_; }
3920 bool DataEquals(HValue* other) OVERRIDE { return true; }
3923 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3924 // The value produced by this instruction is a pointer into the stack
3925 // that looks as if it was a smi because of alignment.
3926 set_representation(Representation::Tagged());
3930 bool IsDeletable() const OVERRIDE { return true; }
3936 class HArgumentsLength FINAL : public HUnaryOperation {
3938 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3940 Representation RequiredInputRepresentation(int index) OVERRIDE {
3941 return Representation::Tagged();
3944 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3947 bool DataEquals(HValue* other) OVERRIDE { return true; }
3950 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
3951 set_representation(Representation::Integer32());
3955 bool IsDeletable() const OVERRIDE { return true; }
3959 class HAccessArgumentsAt FINAL : public HTemplateInstruction<3> {
3961 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
3963 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
3965 Representation RequiredInputRepresentation(int index) OVERRIDE {
3966 // The arguments elements is considered tagged.
3968 ? Representation::Tagged()
3969 : Representation::Integer32();
3972 HValue* arguments() const { return OperandAt(0); }
3973 HValue* length() const { return OperandAt(1); }
3974 HValue* index() const { return OperandAt(2); }
3976 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
3979 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
3980 set_representation(Representation::Tagged());
3982 SetOperandAt(0, arguments);
3983 SetOperandAt(1, length);
3984 SetOperandAt(2, index);
3987 bool DataEquals(HValue* other) OVERRIDE { return true; }
3991 class HBoundsCheckBaseIndexInformation;
3994 class HBoundsCheck FINAL : public HTemplateInstruction<2> {
3996 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
3998 bool skip_check() const { return skip_check_; }
3999 void set_skip_check() { skip_check_ = true; }
4001 HValue* base() const { return base_; }
4002 int offset() const { return offset_; }
4003 int scale() const { return scale_; }
4005 void ApplyIndexChange();
4006 bool DetectCompoundIndex() {
4007 DCHECK(base() == NULL);
4009 DecompositionResult decomposition;
4010 if (index()->TryDecompose(&decomposition)) {
4011 base_ = decomposition.base();
4012 offset_ = decomposition.offset();
4013 scale_ = decomposition.scale();
4023 Representation RequiredInputRepresentation(int index) OVERRIDE {
4024 return representation();
4027 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4028 virtual void InferRepresentation(
4029 HInferRepresentationPhase* h_infer) OVERRIDE;
4031 HValue* index() const { return OperandAt(0); }
4032 HValue* length() const { return OperandAt(1); }
4033 bool allow_equality() const { return allow_equality_; }
4034 void set_allow_equality(bool v) { allow_equality_ = v; }
4036 int RedefinedOperandIndex() OVERRIDE { return 0; }
4037 bool IsPurelyInformativeDefinition() OVERRIDE { return skip_check(); }
4039 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4042 friend class HBoundsCheckBaseIndexInformation;
4044 Range* InferRange(Zone* zone) OVERRIDE;
4046 bool DataEquals(HValue* other) OVERRIDE { return true; }
4051 bool allow_equality_;
4054 // Normally HBoundsCheck should be created using the
4055 // HGraphBuilder::AddBoundsCheck() helper.
4056 // However when building stubs, where we know that the arguments are Int32,
4057 // it makes sense to invoke this constructor directly.
4058 HBoundsCheck(HValue* index, HValue* length)
4059 : skip_check_(false),
4060 base_(NULL), offset_(0), scale_(0),
4061 allow_equality_(false) {
4062 SetOperandAt(0, index);
4063 SetOperandAt(1, length);
4064 SetFlag(kFlexibleRepresentation);
4068 bool IsDeletable() const OVERRIDE { return skip_check() && !FLAG_debug_code; }
4072 class HBoundsCheckBaseIndexInformation FINAL
4073 : public HTemplateInstruction<2> {
4075 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4076 DecompositionResult decomposition;
4077 if (check->index()->TryDecompose(&decomposition)) {
4078 SetOperandAt(0, decomposition.base());
4079 SetOperandAt(1, check);
4085 HValue* base_index() const { return OperandAt(0); }
4086 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4088 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4090 Representation RequiredInputRepresentation(int index) OVERRIDE {
4091 return representation();
4094 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4096 int RedefinedOperandIndex() OVERRIDE { return 0; }
4097 bool IsPurelyInformativeDefinition() OVERRIDE { return true; }
4101 class HBitwiseBinaryOperation : public HBinaryOperation {
4103 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4104 HType type = HType::TaggedNumber())
4105 : HBinaryOperation(context, left, right, type) {
4106 SetFlag(kFlexibleRepresentation);
4107 SetFlag(kTruncatingToInt32);
4108 SetFlag(kAllowUndefinedAsNaN);
4109 SetAllSideEffects();
4112 void RepresentationChanged(Representation to) OVERRIDE {
4113 if (to.IsTagged() &&
4114 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4115 SetAllSideEffects();
4118 ClearAllSideEffects();
4121 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4124 virtual void UpdateRepresentation(Representation new_rep,
4125 HInferRepresentationPhase* h_infer,
4126 const char* reason) OVERRIDE {
4127 // We only generate either int32 or generic tagged bitwise operations.
4128 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4129 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4132 Representation observed_input_representation(int index) OVERRIDE {
4133 Representation r = HBinaryOperation::observed_input_representation(index);
4134 if (r.IsDouble()) return Representation::Integer32();
4138 virtual void initialize_output_representation(
4139 Representation observed) OVERRIDE {
4140 if (observed.IsDouble()) observed = Representation::Integer32();
4141 HBinaryOperation::initialize_output_representation(observed);
4144 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4147 bool IsDeletable() const OVERRIDE { return true; }
4151 class HMathFloorOfDiv FINAL : public HBinaryOperation {
4153 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4157 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4160 bool DataEquals(HValue* other) OVERRIDE { return true; }
4163 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4164 : HBinaryOperation(context, left, right) {
4165 set_representation(Representation::Integer32());
4167 SetFlag(kCanOverflow);
4168 SetFlag(kCanBeDivByZero);
4169 SetFlag(kLeftCanBeMinInt);
4170 SetFlag(kLeftCanBeNegative);
4171 SetFlag(kLeftCanBePositive);
4172 SetFlag(kAllowUndefinedAsNaN);
4175 Range* InferRange(Zone* zone) OVERRIDE;
4177 bool IsDeletable() const OVERRIDE { return true; }
4181 class HArithmeticBinaryOperation : public HBinaryOperation {
4183 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
4184 : HBinaryOperation(context, left, right, HType::TaggedNumber()) {
4185 SetAllSideEffects();
4186 SetFlag(kFlexibleRepresentation);
4187 SetFlag(kAllowUndefinedAsNaN);
4190 void RepresentationChanged(Representation to) OVERRIDE {
4191 if (to.IsTagged() &&
4192 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4193 SetAllSideEffects();
4196 ClearAllSideEffects();
4199 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4202 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4205 bool IsDeletable() const OVERRIDE { return true; }
4209 class HCompareGeneric FINAL : public HBinaryOperation {
4211 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCompareGeneric, HValue*,
4212 HValue*, Token::Value);
4214 Representation RequiredInputRepresentation(int index) OVERRIDE {
4216 ? Representation::Tagged()
4220 Token::Value token() const { return token_; }
4221 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4223 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4226 HCompareGeneric(HValue* context,
4230 : HBinaryOperation(context, left, right, HType::Boolean()),
4232 DCHECK(Token::IsCompareOp(token));
4233 set_representation(Representation::Tagged());
4234 SetAllSideEffects();
4237 Token::Value token_;
4241 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4243 DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch,
4244 HValue*, HValue*, Token::Value);
4245 DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch,
4246 HValue*, HValue*, Token::Value,
4247 HBasicBlock*, HBasicBlock*);
4249 HValue* left() const { return OperandAt(0); }
4250 HValue* right() const { return OperandAt(1); }
4251 Token::Value token() const { return token_; }
4253 void set_observed_input_representation(Representation left,
4254 Representation right) {
4255 observed_input_representation_[0] = left;
4256 observed_input_representation_[1] = right;
4259 virtual void InferRepresentation(
4260 HInferRepresentationPhase* h_infer) OVERRIDE;
4262 Representation RequiredInputRepresentation(int index) OVERRIDE {
4263 return representation();
4265 Representation observed_input_representation(int index) OVERRIDE {
4266 return observed_input_representation_[index];
4269 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4271 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4273 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
4274 SourcePosition right_pos) {
4275 set_operand_position(zone, 0, left_pos);
4276 set_operand_position(zone, 1, right_pos);
4279 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4282 HCompareNumericAndBranch(HValue* left,
4285 HBasicBlock* true_target = NULL,
4286 HBasicBlock* false_target = NULL)
4288 SetFlag(kFlexibleRepresentation);
4289 DCHECK(Token::IsCompareOp(token));
4290 SetOperandAt(0, left);
4291 SetOperandAt(1, right);
4292 SetSuccessorAt(0, true_target);
4293 SetSuccessorAt(1, false_target);
4296 Representation observed_input_representation_[2];
4297 Token::Value token_;
4301 class HCompareHoleAndBranch FINAL : public HUnaryControlInstruction {
4303 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4304 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4305 HBasicBlock*, HBasicBlock*);
4307 virtual void InferRepresentation(
4308 HInferRepresentationPhase* h_infer) OVERRIDE;
4310 Representation RequiredInputRepresentation(int index) OVERRIDE {
4311 return representation();
4314 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4317 HCompareHoleAndBranch(HValue* value,
4318 HBasicBlock* true_target = NULL,
4319 HBasicBlock* false_target = NULL)
4320 : HUnaryControlInstruction(value, true_target, false_target) {
4321 SetFlag(kFlexibleRepresentation);
4322 SetFlag(kAllowUndefinedAsNaN);
4327 class HCompareMinusZeroAndBranch FINAL : public HUnaryControlInstruction {
4329 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4331 virtual void InferRepresentation(
4332 HInferRepresentationPhase* h_infer) OVERRIDE;
4334 Representation RequiredInputRepresentation(int index) OVERRIDE {
4335 return representation();
4338 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4340 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4343 explicit HCompareMinusZeroAndBranch(HValue* value)
4344 : HUnaryControlInstruction(value, NULL, NULL) {
4349 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4351 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4352 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4353 HBasicBlock*, HBasicBlock*);
4355 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4357 static const int kNoKnownSuccessorIndex = -1;
4358 int known_successor_index() const { return known_successor_index_; }
4359 void set_known_successor_index(int known_successor_index) {
4360 known_successor_index_ = known_successor_index;
4363 HValue* left() const { return OperandAt(0); }
4364 HValue* right() const { return OperandAt(1); }
4366 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4368 Representation RequiredInputRepresentation(int index) OVERRIDE {
4369 return Representation::Tagged();
4372 Representation observed_input_representation(int index) OVERRIDE {
4373 return Representation::Tagged();
4376 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4379 HCompareObjectEqAndBranch(HValue* left,
4381 HBasicBlock* true_target = NULL,
4382 HBasicBlock* false_target = NULL)
4383 : known_successor_index_(kNoKnownSuccessorIndex) {
4384 SetOperandAt(0, left);
4385 SetOperandAt(1, right);
4386 SetSuccessorAt(0, true_target);
4387 SetSuccessorAt(1, false_target);
4390 int known_successor_index_;
4394 class HIsObjectAndBranch FINAL : public HUnaryControlInstruction {
4396 DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
4397 DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
4398 HBasicBlock*, HBasicBlock*);
4400 Representation RequiredInputRepresentation(int index) OVERRIDE {
4401 return Representation::Tagged();
4404 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4406 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
4409 HIsObjectAndBranch(HValue* value,
4410 HBasicBlock* true_target = NULL,
4411 HBasicBlock* false_target = NULL)
4412 : HUnaryControlInstruction(value, true_target, false_target) {}
4416 class HIsStringAndBranch FINAL : public HUnaryControlInstruction {
4418 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4419 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4420 HBasicBlock*, HBasicBlock*);
4422 Representation RequiredInputRepresentation(int index) OVERRIDE {
4423 return Representation::Tagged();
4426 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4428 static const int kNoKnownSuccessorIndex = -1;
4429 int known_successor_index() const { return known_successor_index_; }
4430 void set_known_successor_index(int known_successor_index) {
4431 known_successor_index_ = known_successor_index;
4434 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4437 int RedefinedOperandIndex() OVERRIDE { return 0; }
4440 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL,
4441 HBasicBlock* false_target = NULL)
4442 : HUnaryControlInstruction(value, true_target, false_target),
4443 known_successor_index_(kNoKnownSuccessorIndex) {
4444 set_representation(Representation::Tagged());
4447 int known_successor_index_;
4451 class HIsSmiAndBranch FINAL : public HUnaryControlInstruction {
4453 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4454 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4455 HBasicBlock*, HBasicBlock*);
4457 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4459 Representation RequiredInputRepresentation(int index) OVERRIDE {
4460 return Representation::Tagged();
4464 bool DataEquals(HValue* other) OVERRIDE { return true; }
4465 int RedefinedOperandIndex() OVERRIDE { return 0; }
4468 HIsSmiAndBranch(HValue* value,
4469 HBasicBlock* true_target = NULL,
4470 HBasicBlock* false_target = NULL)
4471 : HUnaryControlInstruction(value, true_target, false_target) {
4472 set_representation(Representation::Tagged());
4477 class HIsUndetectableAndBranch FINAL : public HUnaryControlInstruction {
4479 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4480 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4481 HBasicBlock*, HBasicBlock*);
4483 Representation RequiredInputRepresentation(int index) OVERRIDE {
4484 return Representation::Tagged();
4487 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4489 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4492 HIsUndetectableAndBranch(HValue* value,
4493 HBasicBlock* true_target = NULL,
4494 HBasicBlock* false_target = NULL)
4495 : HUnaryControlInstruction(value, true_target, false_target) {}
4499 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4501 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4506 HValue* context() { return OperandAt(0); }
4507 HValue* left() { return OperandAt(1); }
4508 HValue* right() { return OperandAt(2); }
4509 Token::Value token() const { return token_; }
4511 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4513 Representation RequiredInputRepresentation(int index) OVERRIDE {
4514 return Representation::Tagged();
4517 Representation GetInputRepresentation() const {
4518 return Representation::Tagged();
4521 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4524 HStringCompareAndBranch(HValue* context,
4529 DCHECK(Token::IsCompareOp(token));
4530 SetOperandAt(0, context);
4531 SetOperandAt(1, left);
4532 SetOperandAt(2, right);
4533 set_representation(Representation::Tagged());
4534 SetChangesFlag(kNewSpacePromotion);
4537 Token::Value token_;
4541 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4543 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4545 Representation RequiredInputRepresentation(int index) OVERRIDE {
4546 return Representation::None();
4549 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4551 HIsConstructCallAndBranch() {}
4555 class HHasInstanceTypeAndBranch FINAL : public HUnaryControlInstruction {
4557 DECLARE_INSTRUCTION_FACTORY_P2(
4558 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4559 DECLARE_INSTRUCTION_FACTORY_P3(
4560 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4562 InstanceType from() { return from_; }
4563 InstanceType to() { return to_; }
4565 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4567 Representation RequiredInputRepresentation(int index) OVERRIDE {
4568 return Representation::Tagged();
4571 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4573 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4576 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4577 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4578 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4579 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4580 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4584 InstanceType to_; // Inclusive range, not all combinations work.
4588 class HHasCachedArrayIndexAndBranch FINAL : public HUnaryControlInstruction {
4590 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4592 Representation RequiredInputRepresentation(int index) OVERRIDE {
4593 return Representation::Tagged();
4596 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4598 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4599 : HUnaryControlInstruction(value, NULL, NULL) { }
4603 class HGetCachedArrayIndex FINAL : public HUnaryOperation {
4605 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4607 Representation RequiredInputRepresentation(int index) OVERRIDE {
4608 return Representation::Tagged();
4611 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4614 bool DataEquals(HValue* other) OVERRIDE { return true; }
4617 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4618 set_representation(Representation::Tagged());
4622 bool IsDeletable() const OVERRIDE { return true; }
4626 class HClassOfTestAndBranch FINAL : public HUnaryControlInstruction {
4628 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4631 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4633 Representation RequiredInputRepresentation(int index) OVERRIDE {
4634 return Representation::Tagged();
4637 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4639 Handle<String> class_name() const { return class_name_; }
4642 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4643 : HUnaryControlInstruction(value, NULL, NULL),
4644 class_name_(class_name) { }
4646 Handle<String> class_name_;
4650 class HTypeofIsAndBranch FINAL : public HUnaryControlInstruction {
4652 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4654 Handle<String> type_literal() const { return type_literal_.handle(); }
4655 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4657 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4659 Representation RequiredInputRepresentation(int index) OVERRIDE {
4660 return Representation::None();
4663 bool KnownSuccessorBlock(HBasicBlock** block) OVERRIDE;
4665 void FinalizeUniqueness() OVERRIDE {
4666 type_literal_ = Unique<String>(type_literal_.handle());
4670 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4671 : HUnaryControlInstruction(value, NULL, NULL),
4672 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4674 Unique<String> type_literal_;
4678 class HInstanceOf FINAL : public HBinaryOperation {
4680 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4682 Representation RequiredInputRepresentation(int index) OVERRIDE {
4683 return Representation::Tagged();
4686 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
4688 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4691 HInstanceOf(HValue* context, HValue* left, HValue* right)
4692 : HBinaryOperation(context, left, right, HType::Boolean()) {
4693 set_representation(Representation::Tagged());
4694 SetAllSideEffects();
4699 class HInstanceOfKnownGlobal FINAL : public HTemplateInstruction<2> {
4701 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal,
4703 Handle<JSFunction>);
4705 HValue* context() { return OperandAt(0); }
4706 HValue* left() { return OperandAt(1); }
4707 Handle<JSFunction> function() { return function_; }
4709 Representation RequiredInputRepresentation(int index) OVERRIDE {
4710 return Representation::Tagged();
4713 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
4716 HInstanceOfKnownGlobal(HValue* context,
4718 Handle<JSFunction> right)
4719 : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
4720 SetOperandAt(0, context);
4721 SetOperandAt(1, left);
4722 set_representation(Representation::Tagged());
4723 SetAllSideEffects();
4726 Handle<JSFunction> function_;
4730 class HPower FINAL : public HTemplateInstruction<2> {
4732 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4733 HValue* left, HValue* right);
4735 HValue* left() { return OperandAt(0); }
4736 HValue* right() const { return OperandAt(1); }
4738 Representation RequiredInputRepresentation(int index) OVERRIDE {
4740 ? Representation::Double()
4741 : Representation::None();
4743 Representation observed_input_representation(int index) OVERRIDE {
4744 return RequiredInputRepresentation(index);
4747 DECLARE_CONCRETE_INSTRUCTION(Power)
4750 bool DataEquals(HValue* other) OVERRIDE { return true; }
4753 HPower(HValue* left, HValue* right) {
4754 SetOperandAt(0, left);
4755 SetOperandAt(1, right);
4756 set_representation(Representation::Double());
4758 SetChangesFlag(kNewSpacePromotion);
4761 bool IsDeletable() const OVERRIDE {
4762 return !right()->representation().IsTagged();
4767 class HAdd FINAL : public HArithmeticBinaryOperation {
4769 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4770 HValue* left, HValue* right);
4772 // Add is only commutative if two integer values are added and not if two
4773 // tagged values are added (because it might be a String concatenation).
4774 // We also do not commute (pointer + offset).
4775 bool IsCommutative() const OVERRIDE {
4776 return !representation().IsTagged() && !representation().IsExternal();
4779 HValue* Canonicalize() OVERRIDE;
4781 bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
4782 if (left()->IsInteger32Constant()) {
4783 decomposition->Apply(right(), left()->GetInteger32Constant());
4785 } else if (right()->IsInteger32Constant()) {
4786 decomposition->Apply(left(), right()->GetInteger32Constant());
4793 void RepresentationChanged(Representation to) OVERRIDE {
4794 if (to.IsTagged() &&
4795 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4796 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4797 SetAllSideEffects();
4800 ClearAllSideEffects();
4803 if (to.IsTagged()) {
4804 SetChangesFlag(kNewSpacePromotion);
4805 ClearFlag(kAllowUndefinedAsNaN);
4809 Representation RepresentationFromInputs() OVERRIDE;
4811 Representation RequiredInputRepresentation(int index) OVERRIDE;
4813 DECLARE_CONCRETE_INSTRUCTION(Add)
4816 bool DataEquals(HValue* other) OVERRIDE { return true; }
4818 Range* InferRange(Zone* zone) OVERRIDE;
4821 HAdd(HValue* context, HValue* left, HValue* right)
4822 : HArithmeticBinaryOperation(context, left, right) {
4823 SetFlag(kCanOverflow);
4828 class HSub FINAL : public HArithmeticBinaryOperation {
4830 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4831 HValue* left, HValue* right);
4833 HValue* Canonicalize() OVERRIDE;
4835 bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
4836 if (right()->IsInteger32Constant()) {
4837 decomposition->Apply(left(), -right()->GetInteger32Constant());
4844 DECLARE_CONCRETE_INSTRUCTION(Sub)
4847 bool DataEquals(HValue* other) OVERRIDE { return true; }
4849 Range* InferRange(Zone* zone) OVERRIDE;
4852 HSub(HValue* context, HValue* left, HValue* right)
4853 : HArithmeticBinaryOperation(context, left, right) {
4854 SetFlag(kCanOverflow);
4859 class HMul FINAL : public HArithmeticBinaryOperation {
4861 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4862 HValue* left, HValue* right);
4864 static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context,
4865 HValue* left, HValue* right) {
4866 HInstruction* instr = HMul::New(isolate, zone, context, left, right);
4867 if (!instr->IsMul()) return instr;
4868 HMul* mul = HMul::cast(instr);
4869 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4870 mul->AssumeRepresentation(Representation::Integer32());
4871 mul->ClearFlag(HValue::kCanOverflow);
4875 HValue* Canonicalize() OVERRIDE;
4877 // Only commutative if it is certain that not two objects are multiplicated.
4878 bool IsCommutative() const OVERRIDE { return !representation().IsTagged(); }
4880 virtual void UpdateRepresentation(Representation new_rep,
4881 HInferRepresentationPhase* h_infer,
4882 const char* reason) OVERRIDE {
4883 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4888 DECLARE_CONCRETE_INSTRUCTION(Mul)
4891 bool DataEquals(HValue* other) OVERRIDE { return true; }
4893 Range* InferRange(Zone* zone) OVERRIDE;
4896 HMul(HValue* context, HValue* left, HValue* right)
4897 : HArithmeticBinaryOperation(context, left, right) {
4898 SetFlag(kCanOverflow);
4903 class HMod FINAL : public HArithmeticBinaryOperation {
4905 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4906 HValue* left, HValue* right);
4908 HValue* Canonicalize() OVERRIDE;
4910 virtual void UpdateRepresentation(Representation new_rep,
4911 HInferRepresentationPhase* h_infer,
4912 const char* reason) OVERRIDE {
4913 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4914 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4917 DECLARE_CONCRETE_INSTRUCTION(Mod)
4920 bool DataEquals(HValue* other) OVERRIDE { return true; }
4922 Range* InferRange(Zone* zone) OVERRIDE;
4925 HMod(HValue* context,
4927 HValue* right) : HArithmeticBinaryOperation(context, left, right) {
4928 SetFlag(kCanBeDivByZero);
4929 SetFlag(kCanOverflow);
4930 SetFlag(kLeftCanBeNegative);
4935 class HDiv FINAL : public HArithmeticBinaryOperation {
4937 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4938 HValue* left, HValue* right);
4940 HValue* Canonicalize() OVERRIDE;
4942 virtual void UpdateRepresentation(Representation new_rep,
4943 HInferRepresentationPhase* h_infer,
4944 const char* reason) OVERRIDE {
4945 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4946 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4949 DECLARE_CONCRETE_INSTRUCTION(Div)
4952 bool DataEquals(HValue* other) OVERRIDE { return true; }
4954 Range* InferRange(Zone* zone) OVERRIDE;
4957 HDiv(HValue* context, HValue* left, HValue* right)
4958 : HArithmeticBinaryOperation(context, left, right) {
4959 SetFlag(kCanBeDivByZero);
4960 SetFlag(kCanOverflow);
4965 class HMathMinMax FINAL : public HArithmeticBinaryOperation {
4967 enum Operation { kMathMin, kMathMax };
4969 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4970 HValue* left, HValue* right, Operation op);
4972 Representation observed_input_representation(int index) OVERRIDE {
4973 return RequiredInputRepresentation(index);
4976 virtual void InferRepresentation(
4977 HInferRepresentationPhase* h_infer) OVERRIDE;
4979 Representation RepresentationFromInputs() OVERRIDE {
4980 Representation left_rep = left()->representation();
4981 Representation right_rep = right()->representation();
4982 Representation result = Representation::Smi();
4983 result = result.generalize(left_rep);
4984 result = result.generalize(right_rep);
4985 if (result.IsTagged()) return Representation::Double();
4989 bool IsCommutative() const OVERRIDE { return true; }
4991 Operation operation() { return operation_; }
4993 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
4996 bool DataEquals(HValue* other) OVERRIDE {
4997 return other->IsMathMinMax() &&
4998 HMathMinMax::cast(other)->operation_ == operation_;
5001 Range* InferRange(Zone* zone) OVERRIDE;
5004 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5005 : HArithmeticBinaryOperation(context, left, right),
5008 Operation operation_;
5012 class HBitwise FINAL : public HBitwiseBinaryOperation {
5014 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5015 Token::Value op, HValue* left, HValue* right);
5017 Token::Value op() const { return op_; }
5019 bool IsCommutative() const OVERRIDE { return true; }
5021 HValue* Canonicalize() OVERRIDE;
5023 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5025 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5028 bool DataEquals(HValue* other) OVERRIDE {
5029 return op() == HBitwise::cast(other)->op();
5032 Range* InferRange(Zone* zone) OVERRIDE;
5035 HBitwise(HValue* context,
5039 : HBitwiseBinaryOperation(context, left, right),
5041 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5042 // BIT_AND with a smi-range positive value will always unset the
5043 // entire sign-extension of the smi-sign.
5044 if (op == Token::BIT_AND &&
5045 ((left->IsConstant() &&
5046 left->representation().IsSmi() &&
5047 HConstant::cast(left)->Integer32Value() >= 0) ||
5048 (right->IsConstant() &&
5049 right->representation().IsSmi() &&
5050 HConstant::cast(right)->Integer32Value() >= 0))) {
5051 SetFlag(kTruncatingToSmi);
5052 SetFlag(kTruncatingToInt32);
5053 // BIT_OR with a smi-range negative value will always set the entire
5054 // sign-extension of the smi-sign.
5055 } else if (op == Token::BIT_OR &&
5056 ((left->IsConstant() &&
5057 left->representation().IsSmi() &&
5058 HConstant::cast(left)->Integer32Value() < 0) ||
5059 (right->IsConstant() &&
5060 right->representation().IsSmi() &&
5061 HConstant::cast(right)->Integer32Value() < 0))) {
5062 SetFlag(kTruncatingToSmi);
5063 SetFlag(kTruncatingToInt32);
5071 class HShl FINAL : public HBitwiseBinaryOperation {
5073 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5074 HValue* left, HValue* right);
5076 Range* InferRange(Zone* zone) OVERRIDE;
5078 virtual void UpdateRepresentation(Representation new_rep,
5079 HInferRepresentationPhase* h_infer,
5080 const char* reason) OVERRIDE {
5081 if (new_rep.IsSmi() &&
5082 !(right()->IsInteger32Constant() &&
5083 right()->GetInteger32Constant() >= 0)) {
5084 new_rep = Representation::Integer32();
5086 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5089 DECLARE_CONCRETE_INSTRUCTION(Shl)
5092 bool DataEquals(HValue* other) OVERRIDE { return true; }
5095 HShl(HValue* context, HValue* left, HValue* right)
5096 : HBitwiseBinaryOperation(context, left, right) { }
5100 class HShr FINAL : public HBitwiseBinaryOperation {
5102 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5103 HValue* left, HValue* right);
5105 bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
5106 if (right()->IsInteger32Constant()) {
5107 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5108 // This is intended to look for HAdd and HSub, to handle compounds
5109 // like ((base + offset) >> scale) with one single decomposition.
5110 left()->TryDecompose(decomposition);
5117 Range* InferRange(Zone* zone) OVERRIDE;
5119 virtual void UpdateRepresentation(Representation new_rep,
5120 HInferRepresentationPhase* h_infer,
5121 const char* reason) OVERRIDE {
5122 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5123 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5126 DECLARE_CONCRETE_INSTRUCTION(Shr)
5129 bool DataEquals(HValue* other) OVERRIDE { return true; }
5132 HShr(HValue* context, HValue* left, HValue* right)
5133 : HBitwiseBinaryOperation(context, left, right) { }
5137 class HSar FINAL : public HBitwiseBinaryOperation {
5139 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5140 HValue* left, HValue* right);
5142 bool TryDecompose(DecompositionResult* decomposition) OVERRIDE {
5143 if (right()->IsInteger32Constant()) {
5144 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5145 // This is intended to look for HAdd and HSub, to handle compounds
5146 // like ((base + offset) >> scale) with one single decomposition.
5147 left()->TryDecompose(decomposition);
5154 Range* InferRange(Zone* zone) OVERRIDE;
5156 virtual void UpdateRepresentation(Representation new_rep,
5157 HInferRepresentationPhase* h_infer,
5158 const char* reason) OVERRIDE {
5159 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5160 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5163 DECLARE_CONCRETE_INSTRUCTION(Sar)
5166 bool DataEquals(HValue* other) OVERRIDE { return true; }
5169 HSar(HValue* context, HValue* left, HValue* right)
5170 : HBitwiseBinaryOperation(context, left, right) { }
5174 class HRor FINAL : public HBitwiseBinaryOperation {
5176 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5177 HValue* left, HValue* right) {
5178 return new(zone) HRor(context, left, right);
5181 virtual void UpdateRepresentation(Representation new_rep,
5182 HInferRepresentationPhase* h_infer,
5183 const char* reason) OVERRIDE {
5184 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5185 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5188 DECLARE_CONCRETE_INSTRUCTION(Ror)
5191 bool DataEquals(HValue* other) OVERRIDE { return true; }
5194 HRor(HValue* context, HValue* left, HValue* right)
5195 : HBitwiseBinaryOperation(context, left, right) {
5196 ChangeRepresentation(Representation::Integer32());
5201 class HOsrEntry FINAL : public HTemplateInstruction<0> {
5203 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5205 BailoutId ast_id() const { return ast_id_; }
5207 Representation RequiredInputRepresentation(int index) OVERRIDE {
5208 return Representation::None();
5211 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5214 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5215 SetChangesFlag(kOsrEntries);
5216 SetChangesFlag(kNewSpacePromotion);
5223 class HParameter FINAL : public HTemplateInstruction<0> {
5225 enum ParameterKind {
5230 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5231 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5232 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5235 unsigned index() const { return index_; }
5236 ParameterKind kind() const { return kind_; }
5238 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5240 Representation RequiredInputRepresentation(int index) OVERRIDE {
5241 return Representation::None();
5244 Representation KnownOptimalRepresentation() OVERRIDE {
5245 // If a parameter is an input to a phi, that phi should not
5246 // choose any more optimistic representation than Tagged.
5247 return Representation::Tagged();
5250 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5253 explicit HParameter(unsigned index,
5254 ParameterKind kind = STACK_PARAMETER)
5257 set_representation(Representation::Tagged());
5260 explicit HParameter(unsigned index,
5265 set_representation(r);
5269 ParameterKind kind_;
5273 class HCallStub FINAL : public HUnaryCall {
5275 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5276 CodeStub::Major major_key() { return major_key_; }
5278 HValue* context() { return value(); }
5280 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5282 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5285 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5286 : HUnaryCall(context, argument_count),
5287 major_key_(major_key) {
5290 CodeStub::Major major_key_;
5294 class HTailCallThroughMegamorphicCache FINAL : public HInstruction {
5298 CALLED_FROM_KEYED_LOAD = 1 << 0,
5299 PERFORM_MISS_ONLY = 1 << 1
5302 static Flags ComputeFlags(bool called_from_keyed_load,
5303 bool perform_miss_only) {
5305 if (called_from_keyed_load) {
5306 flags = static_cast<Flags>(flags | CALLED_FROM_KEYED_LOAD);
5308 if (perform_miss_only) {
5309 flags = static_cast<Flags>(flags | PERFORM_MISS_ONLY);
5314 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(
5315 HTailCallThroughMegamorphicCache, HValue*, HValue*, HValue*, HValue*,
5316 HTailCallThroughMegamorphicCache::Flags);
5318 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HTailCallThroughMegamorphicCache,
5321 Representation RequiredInputRepresentation(int index) OVERRIDE {
5322 return Representation::Tagged();
5325 virtual int OperandCount() const FINAL OVERRIDE {
5326 return FLAG_vector_ics ? 5 : 3;
5328 virtual HValue* OperandAt(int i) const FINAL OVERRIDE { return inputs_[i]; }
5330 HValue* context() const { return OperandAt(0); }
5331 HValue* receiver() const { return OperandAt(1); }
5332 HValue* name() const { return OperandAt(2); }
5333 HValue* slot() const {
5334 DCHECK(FLAG_vector_ics);
5335 return OperandAt(3);
5337 HValue* vector() const {
5338 DCHECK(FLAG_vector_ics);
5339 return OperandAt(4);
5341 Code::Flags flags() const;
5343 bool is_keyed_load() const { return flags_ & CALLED_FROM_KEYED_LOAD; }
5344 bool is_just_miss() const { return flags_ & PERFORM_MISS_ONLY; }
5346 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5348 DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache)
5351 virtual void InternalSetOperandAt(int i, HValue* value) FINAL OVERRIDE {
5356 HTailCallThroughMegamorphicCache(HValue* context, HValue* receiver,
5357 HValue* name, HValue* slot, HValue* vector,
5360 DCHECK(FLAG_vector_ics);
5361 SetOperandAt(0, context);
5362 SetOperandAt(1, receiver);
5363 SetOperandAt(2, name);
5364 SetOperandAt(3, slot);
5365 SetOperandAt(4, vector);
5368 HTailCallThroughMegamorphicCache(HValue* context, HValue* receiver,
5371 SetOperandAt(0, context);
5372 SetOperandAt(1, receiver);
5373 SetOperandAt(2, name);
5376 EmbeddedContainer<HValue*, 5> inputs_;
5381 class HUnknownOSRValue FINAL : public HTemplateInstruction<0> {
5383 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5385 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5387 Representation RequiredInputRepresentation(int index) OVERRIDE {
5388 return Representation::None();
5391 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5392 HPhi* incoming_value() { return incoming_value_; }
5393 HEnvironment *environment() { return environment_; }
5394 int index() { return index_; }
5396 Representation KnownOptimalRepresentation() OVERRIDE {
5397 if (incoming_value_ == NULL) return Representation::None();
5398 return incoming_value_->KnownOptimalRepresentation();
5401 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5404 HUnknownOSRValue(HEnvironment* environment, int index)
5405 : environment_(environment),
5407 incoming_value_(NULL) {
5408 set_representation(Representation::Tagged());
5411 HEnvironment* environment_;
5413 HPhi* incoming_value_;
5417 class HLoadGlobalGeneric FINAL : public HTemplateInstruction<2> {
5419 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5420 Handle<String>, bool);
5422 HValue* context() { return OperandAt(0); }
5423 HValue* global_object() { return OperandAt(1); }
5424 Handle<String> name() const { return name_; }
5425 bool for_typeof() const { return for_typeof_; }
5426 FeedbackVectorICSlot slot() const { return slot_; }
5427 Handle<TypeFeedbackVector> feedback_vector() const {
5428 return feedback_vector_;
5430 bool HasVectorAndSlot() const { return FLAG_vector_ics; }
5431 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
5432 FeedbackVectorICSlot slot) {
5433 DCHECK(FLAG_vector_ics);
5434 feedback_vector_ = vector;
5438 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5440 Representation RequiredInputRepresentation(int index) OVERRIDE {
5441 return Representation::Tagged();
5444 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5447 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5448 Handle<String> name, bool for_typeof)
5450 for_typeof_(for_typeof),
5451 slot_(FeedbackVectorICSlot::Invalid()) {
5452 SetOperandAt(0, context);
5453 SetOperandAt(1, global_object);
5454 set_representation(Representation::Tagged());
5455 SetAllSideEffects();
5458 Handle<String> name_;
5460 Handle<TypeFeedbackVector> feedback_vector_;
5461 FeedbackVectorICSlot slot_;
5465 class HAllocate FINAL : public HTemplateInstruction<2> {
5467 static bool CompatibleInstanceTypes(InstanceType type1,
5468 InstanceType type2) {
5469 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5470 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5473 static HAllocate* New(
5474 Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type,
5475 PretenureFlag pretenure_flag, InstanceType instance_type,
5476 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) {
5477 return new(zone) HAllocate(context, size, type, pretenure_flag,
5478 instance_type, allocation_site);
5481 // Maximum instance size for which allocations will be inlined.
5482 static const int kMaxInlineSize = 64 * kPointerSize;
5484 HValue* context() const { return OperandAt(0); }
5485 HValue* size() const { return OperandAt(1); }
5487 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5488 HConstant* size_upper_bound() { return size_upper_bound_; }
5489 void set_size_upper_bound(HConstant* value) {
5490 DCHECK(size_upper_bound_ == NULL);
5491 size_upper_bound_ = value;
5494 Representation RequiredInputRepresentation(int index) OVERRIDE {
5496 return Representation::Tagged();
5498 return Representation::Integer32();
5502 Handle<Map> GetMonomorphicJSObjectMap() OVERRIDE {
5503 return known_initial_map_;
5506 void set_known_initial_map(Handle<Map> known_initial_map) {
5507 known_initial_map_ = known_initial_map;
5510 bool IsNewSpaceAllocation() const {
5511 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5514 bool IsOldDataSpaceAllocation() const {
5515 return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0;
5518 bool IsOldPointerSpaceAllocation() const {
5519 return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
5522 bool MustAllocateDoubleAligned() const {
5523 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5526 bool MustPrefillWithFiller() const {
5527 return (flags_ & PREFILL_WITH_FILLER) != 0;
5530 void MakePrefillWithFiller() {
5531 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5534 bool MustClearNextMapWord() const {
5535 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5538 void MakeDoubleAligned() {
5539 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5542 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5543 HValue* dominator) OVERRIDE;
5545 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5547 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5551 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5552 ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
5553 ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
5554 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5555 PREFILL_WITH_FILLER = 1 << 4,
5556 CLEAR_NEXT_MAP_WORD = 1 << 5
5559 HAllocate(HValue* context,
5562 PretenureFlag pretenure_flag,
5563 InstanceType instance_type,
5564 Handle<AllocationSite> allocation_site =
5565 Handle<AllocationSite>::null())
5566 : HTemplateInstruction<2>(type),
5567 flags_(ComputeFlags(pretenure_flag, instance_type)),
5568 dominating_allocate_(NULL),
5569 filler_free_space_size_(NULL),
5570 size_upper_bound_(NULL) {
5571 SetOperandAt(0, context);
5573 set_representation(Representation::Tagged());
5574 SetFlag(kTrackSideEffectDominators);
5575 SetChangesFlag(kNewSpacePromotion);
5576 SetDependsOnFlag(kNewSpacePromotion);
5578 if (FLAG_trace_pretenuring) {
5579 PrintF("HAllocate with AllocationSite %p %s\n",
5580 allocation_site.is_null()
5581 ? static_cast<void*>(NULL)
5582 : static_cast<void*>(*allocation_site),
5583 pretenure_flag == TENURED ? "tenured" : "not tenured");
5587 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5588 InstanceType instance_type) {
5589 Flags flags = pretenure_flag == TENURED
5590 ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
5591 ? ALLOCATE_IN_OLD_POINTER_SPACE
5592 : ALLOCATE_IN_OLD_DATA_SPACE)
5593 : ALLOCATE_IN_NEW_SPACE;
5594 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5595 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5597 // We have to fill the allocated object with one word fillers if we do
5598 // not use allocation folding since some allocations may depend on each
5599 // other, i.e., have a pointer to each other. A GC in between these
5600 // allocations may leave such objects behind in a not completely initialized
5602 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5603 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5605 if (pretenure_flag == NOT_TENURED &&
5606 AllocationSite::CanTrack(instance_type)) {
5607 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5612 void UpdateClearNextMapWord(bool clear_next_map_word) {
5613 flags_ = static_cast<Flags>(clear_next_map_word
5614 ? flags_ | CLEAR_NEXT_MAP_WORD
5615 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5618 void UpdateSize(HValue* size) {
5619 SetOperandAt(1, size);
5620 if (size->IsInteger32Constant()) {
5621 size_upper_bound_ = HConstant::cast(size);
5623 size_upper_bound_ = NULL;
5627 HAllocate* GetFoldableDominator(HAllocate* dominator);
5629 void UpdateFreeSpaceFiller(int32_t filler_size);
5631 void CreateFreeSpaceFiller(int32_t filler_size);
5633 bool IsFoldable(HAllocate* allocate) {
5634 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5635 (IsOldDataSpaceAllocation() &&
5636 allocate->IsOldDataSpaceAllocation()) ||
5637 (IsOldPointerSpaceAllocation() &&
5638 allocate->IsOldPointerSpaceAllocation());
5641 void ClearNextMapWord(int offset);
5644 Handle<Map> known_initial_map_;
5645 HAllocate* dominating_allocate_;
5646 HStoreNamedField* filler_free_space_size_;
5647 HConstant* size_upper_bound_;
5651 class HStoreCodeEntry FINAL: public HTemplateInstruction<2> {
5653 static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context,
5654 HValue* function, HValue* code) {
5655 return new(zone) HStoreCodeEntry(function, code);
5658 Representation RequiredInputRepresentation(int index) OVERRIDE {
5659 return Representation::Tagged();
5662 HValue* function() { return OperandAt(0); }
5663 HValue* code_object() { return OperandAt(1); }
5665 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5668 HStoreCodeEntry(HValue* function, HValue* code) {
5669 SetOperandAt(0, function);
5670 SetOperandAt(1, code);
5675 class HInnerAllocatedObject FINAL : public HTemplateInstruction<2> {
5677 static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone,
5678 HValue* context, HValue* value,
5679 HValue* offset, HType type) {
5680 return new(zone) HInnerAllocatedObject(value, offset, type);
5683 HValue* base_object() const { return OperandAt(0); }
5684 HValue* offset() const { return OperandAt(1); }
5686 Representation RequiredInputRepresentation(int index) OVERRIDE {
5687 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5690 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5692 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5695 HInnerAllocatedObject(HValue* value,
5697 HType type) : HTemplateInstruction<2>(type) {
5698 DCHECK(value->IsAllocate());
5699 DCHECK(type.IsHeapObject());
5700 SetOperandAt(0, value);
5701 SetOperandAt(1, offset);
5702 set_representation(Representation::Tagged());
5707 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5708 return !value->type().IsSmi()
5709 && !value->type().IsNull()
5710 && !value->type().IsBoolean()
5711 && !value->type().IsUndefined()
5712 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5716 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5718 HValue* dominator) {
5719 while (object->IsInnerAllocatedObject()) {
5720 object = HInnerAllocatedObject::cast(object)->base_object();
5722 if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
5725 if (object->IsConstant() &&
5726 HConstant::cast(object)->HasExternalReferenceValue()) {
5727 // Stores to external references require no write barriers
5730 // We definitely need a write barrier unless the object is the allocation
5732 if (object == dominator && object->IsAllocate()) {
5733 // Stores to new space allocations require no write barriers.
5734 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5737 // Stores to old space allocations require no write barriers if the value is
5738 // a constant provably not in new space.
5739 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5742 // Stores to old space allocations require no write barriers if the value is
5743 // an old space allocation.
5744 while (value->IsInnerAllocatedObject()) {
5745 value = HInnerAllocatedObject::cast(value)->base_object();
5747 if (value->IsAllocate() &&
5748 !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5756 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5757 HValue* dominator) {
5758 while (object->IsInnerAllocatedObject()) {
5759 object = HInnerAllocatedObject::cast(object)->base_object();
5761 if (object == dominator &&
5762 object->IsAllocate() &&
5763 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5764 return kPointersToHereAreAlwaysInteresting;
5766 return kPointersToHereMaybeInteresting;
5770 class HLoadContextSlot FINAL : public HUnaryOperation {
5773 // Perform a normal load of the context slot without checking its value.
5775 // Load and check the value of the context slot. Deoptimize if it's the
5776 // hole value. This is used for checking for loading of uninitialized
5777 // harmony bindings where we deoptimize into full-codegen generated code
5778 // which will subsequently throw a reference error.
5780 // Load and check the value of the context slot. Return undefined if it's
5781 // the hole value. This is used for non-harmony const assignments
5782 kCheckReturnUndefined
5785 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5786 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5787 set_representation(Representation::Tagged());
5789 SetDependsOnFlag(kContextSlots);
5792 int slot_index() const { return slot_index_; }
5793 Mode mode() const { return mode_; }
5795 bool DeoptimizesOnHole() {
5796 return mode_ == kCheckDeoptimize;
5799 bool RequiresHoleCheck() const {
5800 return mode_ != kNoCheck;
5803 Representation RequiredInputRepresentation(int index) OVERRIDE {
5804 return Representation::Tagged();
5807 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5809 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5812 bool DataEquals(HValue* other) OVERRIDE {
5813 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5814 return (slot_index() == b->slot_index());
5818 bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
5825 class HStoreContextSlot FINAL : public HTemplateInstruction<2> {
5828 // Perform a normal store to the context slot without checking its previous
5831 // Check the previous value of the context slot and deoptimize if it's the
5832 // hole value. This is used for checking for assignments to uninitialized
5833 // harmony bindings where we deoptimize into full-codegen generated code
5834 // which will subsequently throw a reference error.
5836 // Check the previous value and ignore assignment if it isn't a hole value
5837 kCheckIgnoreAssignment
5840 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5843 HValue* context() const { return OperandAt(0); }
5844 HValue* value() const { return OperandAt(1); }
5845 int slot_index() const { return slot_index_; }
5846 Mode mode() const { return mode_; }
5848 bool NeedsWriteBarrier() {
5849 return StoringValueNeedsWriteBarrier(value());
5852 bool DeoptimizesOnHole() {
5853 return mode_ == kCheckDeoptimize;
5856 bool RequiresHoleCheck() {
5857 return mode_ != kNoCheck;
5860 Representation RequiredInputRepresentation(int index) OVERRIDE {
5861 return Representation::Tagged();
5864 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
5866 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5869 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5870 : slot_index_(slot_index), mode_(mode) {
5871 SetOperandAt(0, context);
5872 SetOperandAt(1, value);
5873 SetChangesFlag(kContextSlots);
5881 // Represents an access to a portion of an object, such as the map pointer,
5882 // array elements pointer, etc, but not accesses to array elements themselves.
5883 class HObjectAccess FINAL {
5885 inline bool IsInobject() const {
5886 return portion() != kBackingStore && portion() != kExternalMemory;
5889 inline bool IsExternalMemory() const {
5890 return portion() == kExternalMemory;
5893 inline bool IsStringLength() const {
5894 return portion() == kStringLengths;
5897 inline bool IsMap() const {
5898 return portion() == kMaps;
5901 inline int offset() const {
5902 return OffsetField::decode(value_);
5905 inline Representation representation() const {
5906 return Representation::FromKind(RepresentationField::decode(value_));
5909 inline Handle<String> name() const {
5913 inline bool immutable() const {
5914 return ImmutableField::decode(value_);
5917 // Returns true if access is being made to an in-object property that
5918 // was already added to the object.
5919 inline bool existing_inobject_property() const {
5920 return ExistingInobjectPropertyField::decode(value_);
5923 inline HObjectAccess WithRepresentation(Representation representation) {
5924 return HObjectAccess(portion(), offset(), representation, name(),
5925 immutable(), existing_inobject_property());
5928 static HObjectAccess ForHeapNumberValue() {
5929 return HObjectAccess(
5930 kDouble, HeapNumber::kValueOffset, Representation::Double());
5933 static HObjectAccess ForHeapNumberValueLowestBits() {
5934 return HObjectAccess(kDouble,
5935 HeapNumber::kValueOffset,
5936 Representation::Integer32());
5939 static HObjectAccess ForHeapNumberValueHighestBits() {
5940 return HObjectAccess(kDouble,
5941 HeapNumber::kValueOffset + kIntSize,
5942 Representation::Integer32());
5945 static HObjectAccess ForElementsPointer() {
5946 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
5949 static HObjectAccess ForLiteralsPointer() {
5950 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
5953 static HObjectAccess ForNextFunctionLinkPointer() {
5954 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
5957 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
5958 return HObjectAccess(
5960 JSArray::kLengthOffset,
5961 IsFastElementsKind(elements_kind)
5962 ? Representation::Smi() : Representation::Tagged());
5965 static HObjectAccess ForAllocationSiteOffset(int offset);
5967 static HObjectAccess ForAllocationSiteList() {
5968 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
5969 Handle<String>::null(), false, false);
5972 static HObjectAccess ForFixedArrayLength() {
5973 return HObjectAccess(
5975 FixedArray::kLengthOffset,
5976 Representation::Smi());
5979 static HObjectAccess ForStringHashField() {
5980 return HObjectAccess(kInobject,
5981 String::kHashFieldOffset,
5982 Representation::Integer32());
5985 static HObjectAccess ForStringLength() {
5986 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
5987 return HObjectAccess(
5989 String::kLengthOffset,
5990 Representation::Smi());
5993 static HObjectAccess ForConsStringFirst() {
5994 return HObjectAccess(kInobject, ConsString::kFirstOffset);
5997 static HObjectAccess ForConsStringSecond() {
5998 return HObjectAccess(kInobject, ConsString::kSecondOffset);
6001 static HObjectAccess ForPropertiesPointer() {
6002 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6005 static HObjectAccess ForPrototypeOrInitialMap() {
6006 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6009 static HObjectAccess ForSharedFunctionInfoPointer() {
6010 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6013 static HObjectAccess ForCodeEntryPointer() {
6014 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6017 static HObjectAccess ForCodeOffset() {
6018 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6021 static HObjectAccess ForOptimizedCodeMap() {
6022 return HObjectAccess(kInobject,
6023 SharedFunctionInfo::kOptimizedCodeMapOffset);
6026 static HObjectAccess ForFunctionContextPointer() {
6027 return HObjectAccess(kInobject, JSFunction::kContextOffset);
6030 static HObjectAccess ForMap() {
6031 return HObjectAccess(kMaps, JSObject::kMapOffset);
6034 static HObjectAccess ForPrototype() {
6035 return HObjectAccess(kMaps, Map::kPrototypeOffset);
6038 static HObjectAccess ForMapAsInteger32() {
6039 return HObjectAccess(kMaps, JSObject::kMapOffset,
6040 Representation::Integer32());
6043 static HObjectAccess ForMapInObjectProperties() {
6044 return HObjectAccess(kInobject,
6045 Map::kInObjectPropertiesOffset,
6046 Representation::UInteger8());
6049 static HObjectAccess ForMapInstanceType() {
6050 return HObjectAccess(kInobject,
6051 Map::kInstanceTypeOffset,
6052 Representation::UInteger8());
6055 static HObjectAccess ForMapInstanceSize() {
6056 return HObjectAccess(kInobject,
6057 Map::kInstanceSizeOffset,
6058 Representation::UInteger8());
6061 static HObjectAccess ForMapBitField() {
6062 return HObjectAccess(kInobject,
6063 Map::kBitFieldOffset,
6064 Representation::UInteger8());
6067 static HObjectAccess ForMapBitField2() {
6068 return HObjectAccess(kInobject,
6069 Map::kBitField2Offset,
6070 Representation::UInteger8());
6073 static HObjectAccess ForNameHashField() {
6074 return HObjectAccess(kInobject,
6075 Name::kHashFieldOffset,
6076 Representation::Integer32());
6079 static HObjectAccess ForMapInstanceTypeAndBitField() {
6080 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6081 // Ensure the two fields share one 16-bit word, endian-independent.
6082 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6083 (Map::kInstanceTypeOffset & ~1));
6084 return HObjectAccess(kInobject,
6085 Map::kInstanceTypeAndBitFieldOffset,
6086 Representation::UInteger16());
6089 static HObjectAccess ForPropertyCellValue() {
6090 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6093 static HObjectAccess ForCellValue() {
6094 return HObjectAccess(kInobject, Cell::kValueOffset);
6097 static HObjectAccess ForWeakCellValue() {
6098 return HObjectAccess(kInobject, WeakCell::kValueOffset);
6101 static HObjectAccess ForWeakCellNext() {
6102 return HObjectAccess(kInobject, WeakCell::kNextOffset);
6105 static HObjectAccess ForAllocationMementoSite() {
6106 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6109 static HObjectAccess ForCounter() {
6110 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6111 Handle<String>::null(), false, false);
6114 static HObjectAccess ForExternalUInteger8() {
6115 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6116 Handle<String>::null(), false, false);
6119 // Create an access to an offset in a fixed array header.
6120 static HObjectAccess ForFixedArrayHeader(int offset);
6122 // Create an access to an in-object property in a JSObject.
6123 // This kind of access must be used when the object |map| is known and
6124 // in-object properties are being accessed. Accesses of the in-object
6125 // properties can have different semantics depending on whether corresponding
6126 // property was added to the map or not.
6127 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6128 Representation representation = Representation::Tagged());
6130 // Create an access to an in-object property in a JSObject.
6131 // This kind of access can be used for accessing object header fields or
6132 // in-object properties if the map of the object is not known.
6133 static HObjectAccess ForObservableJSObjectOffset(int offset,
6134 Representation representation = Representation::Tagged()) {
6135 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6138 // Create an access to an in-object property in a JSArray.
6139 static HObjectAccess ForJSArrayOffset(int offset);
6141 static HObjectAccess ForContextSlot(int index);
6143 static HObjectAccess ForScriptContext(int index);
6145 // Create an access to the backing store of an object.
6146 static HObjectAccess ForBackingStoreOffset(int offset,
6147 Representation representation = Representation::Tagged());
6149 // Create an access to a resolved field (in-object or backing store).
6150 static HObjectAccess ForField(Handle<Map> map, int index,
6151 Representation representation,
6152 Handle<String> name);
6154 static HObjectAccess ForJSTypedArrayLength() {
6155 return HObjectAccess::ForObservableJSObjectOffset(
6156 JSTypedArray::kLengthOffset);
6159 static HObjectAccess ForJSArrayBufferBackingStore() {
6160 return HObjectAccess::ForObservableJSObjectOffset(
6161 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6164 static HObjectAccess ForJSArrayBufferByteLength() {
6165 return HObjectAccess::ForObservableJSObjectOffset(
6166 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6169 static HObjectAccess ForExternalArrayExternalPointer() {
6170 return HObjectAccess::ForObservableJSObjectOffset(
6171 ExternalArray::kExternalPointerOffset, Representation::External());
6174 static HObjectAccess ForJSArrayBufferViewWeakNext() {
6175 return HObjectAccess::ForObservableJSObjectOffset(
6176 JSArrayBufferView::kWeakNextOffset);
6179 static HObjectAccess ForJSArrayBufferWeakFirstView() {
6180 return HObjectAccess::ForObservableJSObjectOffset(
6181 JSArrayBuffer::kWeakFirstViewOffset);
6184 static HObjectAccess ForJSArrayBufferViewBuffer() {
6185 return HObjectAccess::ForObservableJSObjectOffset(
6186 JSArrayBufferView::kBufferOffset);
6189 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6190 return HObjectAccess::ForObservableJSObjectOffset(
6191 JSArrayBufferView::kByteOffsetOffset);
6194 static HObjectAccess ForJSArrayBufferViewByteLength() {
6195 return HObjectAccess::ForObservableJSObjectOffset(
6196 JSArrayBufferView::kByteLengthOffset);
6199 static HObjectAccess ForGlobalObjectNativeContext() {
6200 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6203 static HObjectAccess ForJSCollectionTable() {
6204 return HObjectAccess::ForObservableJSObjectOffset(
6205 JSCollection::kTableOffset);
6208 template <typename CollectionType>
6209 static HObjectAccess ForOrderedHashTableNumberOfBuckets() {
6210 return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset,
6211 Representation::Smi());
6214 template <typename CollectionType>
6215 static HObjectAccess ForOrderedHashTableNumberOfElements() {
6216 return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset,
6217 Representation::Smi());
6220 template <typename CollectionType>
6221 static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() {
6222 return HObjectAccess(kInobject,
6223 CollectionType::kNumberOfDeletedElementsOffset,
6224 Representation::Smi());
6227 template <typename CollectionType>
6228 static HObjectAccess ForOrderedHashTableNextTable() {
6229 return HObjectAccess(kInobject, CollectionType::kNextTableOffset);
6232 template <typename CollectionType>
6233 static HObjectAccess ForOrderedHashTableBucket(int bucket) {
6234 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6235 (bucket * kPointerSize),
6236 Representation::Smi());
6239 // Access into the data table of an OrderedHashTable with a
6240 // known-at-compile-time bucket count.
6241 template <typename CollectionType, int kBucketCount>
6242 static HObjectAccess ForOrderedHashTableDataTableIndex(int index) {
6243 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6244 (kBucketCount * kPointerSize) +
6245 (index * kPointerSize));
6248 inline bool Equals(HObjectAccess that) const {
6249 return value_ == that.value_; // portion and offset must match
6253 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6256 // internal use only; different parts of an object or array
6258 kMaps, // map of an object
6259 kArrayLengths, // the length of an array
6260 kStringLengths, // the length of a string
6261 kElementsPointer, // elements pointer
6262 kBackingStore, // some field in the backing store
6263 kDouble, // some double field
6264 kInobject, // some other in-object field
6265 kExternalMemory // some field in external memory
6268 HObjectAccess() : value_(0) {}
6270 HObjectAccess(Portion portion, int offset,
6271 Representation representation = Representation::Tagged(),
6272 Handle<String> name = Handle<String>::null(),
6273 bool immutable = false,
6274 bool existing_inobject_property = true)
6275 : value_(PortionField::encode(portion) |
6276 RepresentationField::encode(representation.kind()) |
6277 ImmutableField::encode(immutable ? 1 : 0) |
6278 ExistingInobjectPropertyField::encode(
6279 existing_inobject_property ? 1 : 0) |
6280 OffsetField::encode(offset)),
6282 // assert that the fields decode correctly
6283 DCHECK(this->offset() == offset);
6284 DCHECK(this->portion() == portion);
6285 DCHECK(this->immutable() == immutable);
6286 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6287 DCHECK(RepresentationField::decode(value_) == representation.kind());
6288 DCHECK(!this->existing_inobject_property() || IsInobject());
6291 class PortionField : public BitField<Portion, 0, 3> {};
6292 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6293 class ImmutableField : public BitField<bool, 7, 1> {};
6294 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6295 class OffsetField : public BitField<int, 9, 23> {};
6297 uint32_t value_; // encodes portion, representation, immutable, and offset
6298 Handle<String> name_;
6300 friend class HLoadNamedField;
6301 friend class HStoreNamedField;
6302 friend class SideEffectsTracker;
6303 friend std::ostream& operator<<(std::ostream& os,
6304 const HObjectAccess& access);
6306 inline Portion portion() const {
6307 return PortionField::decode(value_);
6312 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access);
6315 class HLoadNamedField FINAL : public HTemplateInstruction<2> {
6317 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6318 HValue*, HObjectAccess);
6319 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6320 HObjectAccess, const UniqueSet<Map>*, HType);
6322 HValue* object() const { return OperandAt(0); }
6323 HValue* dependency() const {
6324 DCHECK(HasDependency());
6325 return OperandAt(1);
6327 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6328 HObjectAccess access() const { return access_; }
6329 Representation field_representation() const {
6330 return access_.representation();
6333 const UniqueSet<Map>* maps() const { return maps_; }
6335 bool HasEscapingOperandAt(int index) OVERRIDE { return false; }
6336 bool HasOutOfBoundsAccess(int size) OVERRIDE {
6337 return !access().IsInobject() || access().offset() >= size;
6339 Representation RequiredInputRepresentation(int index) OVERRIDE {
6341 // object must be external in case of external memory access
6342 return access().IsExternalMemory() ? Representation::External()
6343 : Representation::Tagged();
6346 return Representation::None();
6348 Range* InferRange(Zone* zone) OVERRIDE;
6349 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6351 bool CanBeReplacedWith(HValue* other) const {
6352 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6353 if (!type().Equals(other->type())) return false;
6354 if (!representation().Equals(other->representation())) return false;
6355 if (!other->IsLoadNamedField()) return true;
6356 HLoadNamedField* that = HLoadNamedField::cast(other);
6357 if (this->maps_ == that->maps_) return true;
6358 if (this->maps_ == NULL || that->maps_ == NULL) return false;
6359 return this->maps_->IsSubset(that->maps_);
6362 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6365 bool DataEquals(HValue* other) OVERRIDE {
6366 HLoadNamedField* that = HLoadNamedField::cast(other);
6367 if (!this->access_.Equals(that->access_)) return false;
6368 if (this->maps_ == that->maps_) return true;
6369 return (this->maps_ != NULL &&
6370 that->maps_ != NULL &&
6371 this->maps_->Equals(that->maps_));
6375 HLoadNamedField(HValue* object,
6377 HObjectAccess access)
6378 : access_(access), maps_(NULL) {
6379 DCHECK_NOT_NULL(object);
6380 SetOperandAt(0, object);
6381 SetOperandAt(1, dependency ? dependency : object);
6383 Representation representation = access.representation();
6384 if (representation.IsInteger8() ||
6385 representation.IsUInteger8() ||
6386 representation.IsInteger16() ||
6387 representation.IsUInteger16()) {
6388 set_representation(Representation::Integer32());
6389 } else if (representation.IsSmi()) {
6390 set_type(HType::Smi());
6391 if (SmiValuesAre32Bits()) {
6392 set_representation(Representation::Integer32());
6394 set_representation(representation);
6396 } else if (representation.IsDouble() ||
6397 representation.IsExternal() ||
6398 representation.IsInteger32()) {
6399 set_representation(representation);
6400 } else if (representation.IsHeapObject()) {
6401 set_type(HType::HeapObject());
6402 set_representation(Representation::Tagged());
6404 set_representation(Representation::Tagged());
6406 access.SetGVNFlags(this, LOAD);
6409 HLoadNamedField(HValue* object,
6411 HObjectAccess access,
6412 const UniqueSet<Map>* maps,
6414 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6415 DCHECK_NOT_NULL(maps);
6416 DCHECK_NE(0, maps->size());
6418 DCHECK_NOT_NULL(object);
6419 SetOperandAt(0, object);
6420 SetOperandAt(1, dependency ? dependency : object);
6422 DCHECK(access.representation().IsHeapObject());
6423 DCHECK(type.IsHeapObject());
6424 set_representation(Representation::Tagged());
6426 access.SetGVNFlags(this, LOAD);
6429 bool IsDeletable() const OVERRIDE { return true; }
6431 HObjectAccess access_;
6432 const UniqueSet<Map>* maps_;
6436 class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
6438 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadNamedGeneric, HValue*,
6439 Handle<Object>, InlineCacheState);
6441 HValue* context() const { return OperandAt(0); }
6442 HValue* object() const { return OperandAt(1); }
6443 Handle<Object> name() const { return name_; }
6445 InlineCacheState initialization_state() const {
6446 return initialization_state_;
6448 FeedbackVectorICSlot slot() const { return slot_; }
6449 Handle<TypeFeedbackVector> feedback_vector() const {
6450 return feedback_vector_;
6452 bool HasVectorAndSlot() const { return FLAG_vector_ics; }
6453 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6454 FeedbackVectorICSlot slot) {
6455 DCHECK(FLAG_vector_ics);
6456 feedback_vector_ = vector;
6460 Representation RequiredInputRepresentation(int index) OVERRIDE {
6461 return Representation::Tagged();
6464 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6466 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6469 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name,
6470 InlineCacheState initialization_state)
6472 slot_(FeedbackVectorICSlot::Invalid()),
6473 initialization_state_(initialization_state) {
6474 SetOperandAt(0, context);
6475 SetOperandAt(1, object);
6476 set_representation(Representation::Tagged());
6477 SetAllSideEffects();
6480 Handle<Object> name_;
6481 Handle<TypeFeedbackVector> feedback_vector_;
6482 FeedbackVectorICSlot slot_;
6483 InlineCacheState initialization_state_;
6487 class HLoadFunctionPrototype FINAL : public HUnaryOperation {
6489 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6491 HValue* function() { return OperandAt(0); }
6493 Representation RequiredInputRepresentation(int index) OVERRIDE {
6494 return Representation::Tagged();
6497 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6500 bool DataEquals(HValue* other) OVERRIDE { return true; }
6503 explicit HLoadFunctionPrototype(HValue* function)
6504 : HUnaryOperation(function) {
6505 set_representation(Representation::Tagged());
6507 SetDependsOnFlag(kCalls);
6511 class ArrayInstructionInterface {
6513 virtual HValue* GetKey() = 0;
6514 virtual void SetKey(HValue* key) = 0;
6515 virtual ElementsKind elements_kind() const = 0;
6516 // TryIncreaseBaseOffset returns false if overflow would result.
6517 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6518 virtual bool IsDehoisted() const = 0;
6519 virtual void SetDehoisted(bool is_dehoisted) = 0;
6520 virtual ~ArrayInstructionInterface() { }
6522 static Representation KeyedAccessIndexRequirement(Representation r) {
6523 return r.IsInteger32() || SmiValuesAre32Bits()
6524 ? Representation::Integer32() : Representation::Smi();
6529 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6531 enum LoadKeyedHoleMode {
6537 class HLoadKeyed FINAL
6538 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6540 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6542 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6543 ElementsKind, LoadKeyedHoleMode);
6544 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6545 ElementsKind, LoadKeyedHoleMode, int);
6547 bool is_external() const {
6548 return IsExternalArrayElementsKind(elements_kind());
6550 bool is_fixed_typed_array() const {
6551 return IsFixedTypedArrayElementsKind(elements_kind());
6553 bool is_typed_elements() const {
6554 return is_external() || is_fixed_typed_array();
6556 HValue* elements() const { return OperandAt(0); }
6557 HValue* key() const { return OperandAt(1); }
6558 HValue* dependency() const {
6559 DCHECK(HasDependency());
6560 return OperandAt(2);
6562 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6563 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6564 bool TryIncreaseBaseOffset(uint32_t increase_by_value) OVERRIDE;
6565 HValue* GetKey() OVERRIDE { return key(); }
6566 void SetKey(HValue* key) OVERRIDE { SetOperandAt(1, key); }
6567 bool IsDehoisted() const OVERRIDE {
6568 return IsDehoistedField::decode(bit_field_);
6570 void SetDehoisted(bool is_dehoisted) OVERRIDE {
6571 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6573 ElementsKind elements_kind() const OVERRIDE {
6574 return ElementsKindField::decode(bit_field_);
6576 LoadKeyedHoleMode hole_mode() const {
6577 return HoleModeField::decode(bit_field_);
6580 Representation RequiredInputRepresentation(int index) OVERRIDE {
6581 // kind_fast: tagged[int32] (none)
6582 // kind_double: tagged[int32] (none)
6583 // kind_fixed_typed_array: tagged[int32] (none)
6584 // kind_external: external[int32] (none)
6586 return is_external() ? Representation::External()
6587 : Representation::Tagged();
6590 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6591 OperandAt(1)->representation());
6593 return Representation::None();
6596 Representation observed_input_representation(int index) OVERRIDE {
6597 return RequiredInputRepresentation(index);
6600 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6602 bool UsesMustHandleHole() const;
6603 bool AllUsesCanTreatHoleAsNaN() const;
6604 bool RequiresHoleCheck() const;
6606 Range* InferRange(Zone* zone) OVERRIDE;
6608 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6611 bool DataEquals(HValue* other) OVERRIDE {
6612 if (!other->IsLoadKeyed()) return false;
6613 HLoadKeyed* other_load = HLoadKeyed::cast(other);
6615 if (base_offset() != other_load->base_offset()) return false;
6616 return elements_kind() == other_load->elements_kind();
6620 HLoadKeyed(HValue* obj,
6623 ElementsKind elements_kind,
6624 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6625 int offset = kDefaultKeyedHeaderOffsetSentinel)
6627 offset = offset == kDefaultKeyedHeaderOffsetSentinel
6628 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6630 bit_field_ = ElementsKindField::encode(elements_kind) |
6631 HoleModeField::encode(mode) |
6632 BaseOffsetField::encode(offset);
6634 SetOperandAt(0, obj);
6635 SetOperandAt(1, key);
6636 SetOperandAt(2, dependency != NULL ? dependency : obj);
6638 if (!is_typed_elements()) {
6639 // I can detect the case between storing double (holey and fast) and
6640 // smi/object by looking at elements_kind_.
6641 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6642 IsFastDoubleElementsKind(elements_kind));
6644 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6645 if (IsFastSmiElementsKind(elements_kind) &&
6646 (!IsHoleyElementsKind(elements_kind) ||
6647 mode == NEVER_RETURN_HOLE)) {
6648 set_type(HType::Smi());
6649 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6650 set_representation(Representation::Integer32());
6652 set_representation(Representation::Smi());
6655 set_representation(Representation::Tagged());
6658 SetDependsOnFlag(kArrayElements);
6660 set_representation(Representation::Double());
6661 SetDependsOnFlag(kDoubleArrayElements);
6664 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
6665 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
6666 elements_kind == FLOAT32_ELEMENTS ||
6667 elements_kind == FLOAT64_ELEMENTS) {
6668 set_representation(Representation::Double());
6670 set_representation(Representation::Integer32());
6673 if (is_external()) {
6674 SetDependsOnFlag(kExternalMemory);
6675 } else if (is_fixed_typed_array()) {
6676 SetDependsOnFlag(kTypedArrayElements);
6680 // Native code could change the specialized array.
6681 SetDependsOnFlag(kCalls);
6687 bool IsDeletable() const OVERRIDE { return !RequiresHoleCheck(); }
6689 // Establish some checks around our packed fields
6690 enum LoadKeyedBits {
6691 kBitsForElementsKind = 5,
6692 kBitsForHoleMode = 1,
6693 kBitsForBaseOffset = 25,
6694 kBitsForIsDehoisted = 1,
6696 kStartElementsKind = 0,
6697 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6698 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6699 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6702 STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset +
6703 kBitsForIsDehoisted) <= sizeof(uint32_t) * 8);
6704 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6705 class ElementsKindField:
6706 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6708 class HoleModeField:
6709 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6711 class BaseOffsetField:
6712 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6714 class IsDehoistedField:
6715 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6717 uint32_t bit_field_;
6721 class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
6723 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadKeyedGeneric, HValue*,
6724 HValue*, InlineCacheState);
6725 HValue* object() const { return OperandAt(0); }
6726 HValue* key() const { return OperandAt(1); }
6727 HValue* context() const { return OperandAt(2); }
6728 InlineCacheState initialization_state() const {
6729 return initialization_state_;
6731 FeedbackVectorICSlot slot() const { return slot_; }
6732 Handle<TypeFeedbackVector> feedback_vector() const {
6733 return feedback_vector_;
6735 bool HasVectorAndSlot() const { return FLAG_vector_ics; }
6736 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
6737 FeedbackVectorICSlot slot) {
6738 DCHECK(FLAG_vector_ics);
6739 feedback_vector_ = vector;
6743 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6745 Representation RequiredInputRepresentation(int index) OVERRIDE {
6747 return Representation::Tagged();
6750 HValue* Canonicalize() OVERRIDE;
6752 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6755 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key,
6756 InlineCacheState initialization_state)
6757 : slot_(FeedbackVectorICSlot::Invalid()),
6758 initialization_state_(initialization_state) {
6759 set_representation(Representation::Tagged());
6760 SetOperandAt(0, obj);
6761 SetOperandAt(1, key);
6762 SetOperandAt(2, context);
6763 SetAllSideEffects();
6766 Handle<TypeFeedbackVector> feedback_vector_;
6767 FeedbackVectorICSlot slot_;
6768 InlineCacheState initialization_state_;
6772 // Indicates whether the store is a store to an entry that was previously
6773 // initialized or not.
6774 enum StoreFieldOrKeyedMode {
6775 // The entry could be either previously initialized or not.
6777 // At the time of this store it is guaranteed that the entry is already
6779 STORE_TO_INITIALIZED_ENTRY
6783 class HStoreNamedField FINAL : public HTemplateInstruction<3> {
6785 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6786 HObjectAccess, HValue*);
6787 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6788 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6790 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6792 bool HasEscapingOperandAt(int index) OVERRIDE { return index == 1; }
6793 bool HasOutOfBoundsAccess(int size) OVERRIDE {
6794 return !access().IsInobject() || access().offset() >= size;
6796 Representation RequiredInputRepresentation(int index) OVERRIDE {
6797 if (index == 0 && access().IsExternalMemory()) {
6798 // object must be external in case of external memory access
6799 return Representation::External();
6800 } else if (index == 1) {
6801 if (field_representation().IsInteger8() ||
6802 field_representation().IsUInteger8() ||
6803 field_representation().IsInteger16() ||
6804 field_representation().IsUInteger16() ||
6805 field_representation().IsInteger32()) {
6806 return Representation::Integer32();
6807 } else if (field_representation().IsDouble()) {
6808 return field_representation();
6809 } else if (field_representation().IsSmi()) {
6810 if (SmiValuesAre32Bits() &&
6811 store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6812 return Representation::Integer32();
6814 return field_representation();
6815 } else if (field_representation().IsExternal()) {
6816 return Representation::External();
6819 return Representation::Tagged();
6821 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6822 HValue* dominator) OVERRIDE {
6823 DCHECK(side_effect == kNewSpacePromotion);
6824 if (!FLAG_use_write_barrier_elimination) return false;
6825 dominator_ = dominator;
6828 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6830 HValue* object() const { return OperandAt(0); }
6831 HValue* value() const { return OperandAt(1); }
6832 HValue* transition() const { return OperandAt(2); }
6834 HObjectAccess access() const { return access_; }
6835 HValue* dominator() const { return dominator_; }
6836 bool has_transition() const { return HasTransitionField::decode(bit_field_); }
6837 StoreFieldOrKeyedMode store_mode() const {
6838 return StoreModeField::decode(bit_field_);
6841 Handle<Map> transition_map() const {
6842 if (has_transition()) {
6843 return Handle<Map>::cast(
6844 HConstant::cast(transition())->handle(Isolate::Current()));
6846 return Handle<Map>();
6850 void SetTransition(HConstant* transition) {
6851 DCHECK(!has_transition()); // Only set once.
6852 SetOperandAt(2, transition);
6853 bit_field_ = HasTransitionField::update(bit_field_, true);
6854 SetChangesFlag(kMaps);
6857 bool NeedsWriteBarrier() const {
6858 DCHECK(!field_representation().IsDouble() ||
6859 (FLAG_unbox_double_fields && access_.IsInobject()) ||
6861 if (field_representation().IsDouble()) return false;
6862 if (field_representation().IsSmi()) return false;
6863 if (field_representation().IsInteger32()) return false;
6864 if (field_representation().IsExternal()) return false;
6865 return StoringValueNeedsWriteBarrier(value()) &&
6866 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6869 bool NeedsWriteBarrierForMap() {
6870 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6874 SmiCheck SmiCheckForWriteBarrier() const {
6875 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6876 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6877 return INLINE_SMI_CHECK;
6880 PointersToHereCheck PointersToHereCheckForValue() const {
6881 return PointersToHereCheckForObject(value(), dominator());
6884 Representation field_representation() const {
6885 return access_.representation();
6888 void UpdateValue(HValue* value) {
6889 SetOperandAt(1, value);
6892 bool CanBeReplacedWith(HStoreNamedField* that) const {
6893 if (!this->access().Equals(that->access())) return false;
6894 if (SmiValuesAre32Bits() &&
6895 this->field_representation().IsSmi() &&
6896 this->store_mode() == INITIALIZING_STORE &&
6897 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6898 // We cannot replace an initializing store to a smi field with a store to
6899 // an initialized entry on 64-bit architectures (with 32-bit smis).
6906 HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val,
6907 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6910 bit_field_(HasTransitionField::encode(false) |
6911 StoreModeField::encode(store_mode)) {
6912 // Stores to a non existing in-object property are allowed only to the
6913 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6914 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6915 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6916 SetOperandAt(0, obj);
6917 SetOperandAt(1, val);
6918 SetOperandAt(2, obj);
6919 access.SetGVNFlags(this, STORE);
6922 class HasTransitionField : public BitField<bool, 0, 1> {};
6923 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {};
6925 HObjectAccess access_;
6927 uint32_t bit_field_;
6931 class HStoreNamedGeneric FINAL : public HTemplateInstruction<3> {
6933 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreNamedGeneric, HValue*,
6934 Handle<String>, HValue*,
6935 LanguageMode, InlineCacheState);
6936 HValue* object() const { return OperandAt(0); }
6937 HValue* value() const { return OperandAt(1); }
6938 HValue* context() const { return OperandAt(2); }
6939 Handle<String> name() const { return name_; }
6940 LanguageMode language_mode() const { return language_mode_; }
6941 InlineCacheState initialization_state() const {
6942 return initialization_state_;
6945 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
6947 Representation RequiredInputRepresentation(int index) OVERRIDE {
6948 return Representation::Tagged();
6951 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
6954 HStoreNamedGeneric(HValue* context, HValue* object, Handle<String> name,
6955 HValue* value, LanguageMode language_mode,
6956 InlineCacheState initialization_state)
6958 language_mode_(language_mode),
6959 initialization_state_(initialization_state) {
6960 SetOperandAt(0, object);
6961 SetOperandAt(1, value);
6962 SetOperandAt(2, context);
6963 SetAllSideEffects();
6966 Handle<String> name_;
6967 LanguageMode language_mode_;
6968 InlineCacheState initialization_state_;
6972 class HStoreKeyed FINAL
6973 : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6975 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
6977 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
6978 ElementsKind, StoreFieldOrKeyedMode);
6979 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
6980 ElementsKind, StoreFieldOrKeyedMode, int);
6982 Representation RequiredInputRepresentation(int index) OVERRIDE {
6983 // kind_fast: tagged[int32] = tagged
6984 // kind_double: tagged[int32] = double
6985 // kind_smi : tagged[int32] = smi
6986 // kind_fixed_typed_array: tagged[int32] = (double | int32)
6987 // kind_external: external[int32] = (double | int32)
6989 return is_external() ? Representation::External()
6990 : Representation::Tagged();
6991 } else if (index == 1) {
6992 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6993 OperandAt(1)->representation());
6996 DCHECK_EQ(index, 2);
6997 return RequiredValueRepresentation(elements_kind(), store_mode());
7000 static Representation RequiredValueRepresentation(
7001 ElementsKind kind, StoreFieldOrKeyedMode mode) {
7002 if (IsDoubleOrFloatElementsKind(kind)) {
7003 return Representation::Double();
7006 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
7007 mode == STORE_TO_INITIALIZED_ENTRY) {
7008 return Representation::Integer32();
7011 if (IsFastSmiElementsKind(kind)) {
7012 return Representation::Smi();
7015 return IsExternalArrayElementsKind(kind) ||
7016 IsFixedTypedArrayElementsKind(kind)
7017 ? Representation::Integer32()
7018 : Representation::Tagged();
7021 bool is_external() const {
7022 return IsExternalArrayElementsKind(elements_kind());
7025 bool is_fixed_typed_array() const {
7026 return IsFixedTypedArrayElementsKind(elements_kind());
7029 bool is_typed_elements() const {
7030 return is_external() || is_fixed_typed_array();
7033 Representation observed_input_representation(int index) OVERRIDE {
7034 if (index < 2) return RequiredInputRepresentation(index);
7035 if (IsUninitialized()) {
7036 return Representation::None();
7039 RequiredValueRepresentation(elements_kind(), store_mode());
7040 // For fast object elements kinds, don't assume anything.
7041 if (r.IsTagged()) return Representation::None();
7045 HValue* elements() const { return OperandAt(0); }
7046 HValue* key() const { return OperandAt(1); }
7047 HValue* value() const { return OperandAt(2); }
7048 bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); }
7049 StoreFieldOrKeyedMode store_mode() const {
7050 return StoreModeField::decode(bit_field_);
7052 ElementsKind elements_kind() const OVERRIDE {
7053 return ElementsKindField::decode(bit_field_);
7055 uint32_t base_offset() const { return base_offset_; }
7056 bool TryIncreaseBaseOffset(uint32_t increase_by_value) OVERRIDE;
7057 HValue* GetKey() OVERRIDE { return key(); }
7058 void SetKey(HValue* key) OVERRIDE { SetOperandAt(1, key); }
7059 bool IsDehoisted() const OVERRIDE {
7060 return IsDehoistedField::decode(bit_field_);
7062 void SetDehoisted(bool is_dehoisted) OVERRIDE {
7063 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
7065 bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); }
7066 void SetUninitialized(bool is_uninitialized) {
7067 bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized);
7070 bool IsConstantHoleStore() {
7071 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7074 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7075 HValue* dominator) OVERRIDE {
7076 DCHECK(side_effect == kNewSpacePromotion);
7077 dominator_ = dominator;
7081 HValue* dominator() const { return dominator_; }
7083 bool NeedsWriteBarrier() {
7084 if (value_is_smi()) {
7087 return StoringValueNeedsWriteBarrier(value()) &&
7088 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7092 PointersToHereCheck PointersToHereCheckForValue() const {
7093 return PointersToHereCheckForObject(value(), dominator());
7096 bool NeedsCanonicalization();
7098 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7100 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7103 HStoreKeyed(HValue* obj, HValue* key, HValue* val, ElementsKind elements_kind,
7104 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7105 int offset = kDefaultKeyedHeaderOffsetSentinel)
7106 : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7107 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7109 bit_field_(IsDehoistedField::encode(false) |
7110 IsUninitializedField::encode(false) |
7111 StoreModeField::encode(store_mode) |
7112 ElementsKindField::encode(elements_kind)),
7114 SetOperandAt(0, obj);
7115 SetOperandAt(1, key);
7116 SetOperandAt(2, val);
7118 if (IsFastObjectElementsKind(elements_kind)) {
7119 SetFlag(kTrackSideEffectDominators);
7120 SetDependsOnFlag(kNewSpacePromotion);
7122 if (is_external()) {
7123 SetChangesFlag(kExternalMemory);
7124 SetFlag(kAllowUndefinedAsNaN);
7125 } else if (IsFastDoubleElementsKind(elements_kind)) {
7126 SetChangesFlag(kDoubleArrayElements);
7127 } else if (IsFastSmiElementsKind(elements_kind)) {
7128 SetChangesFlag(kArrayElements);
7129 } else if (is_fixed_typed_array()) {
7130 SetChangesFlag(kTypedArrayElements);
7131 SetFlag(kAllowUndefinedAsNaN);
7133 SetChangesFlag(kArrayElements);
7136 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7137 if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
7138 elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
7139 (elements_kind >= UINT8_ELEMENTS &&
7140 elements_kind <= INT32_ELEMENTS)) {
7141 SetFlag(kTruncatingToInt32);
7145 class IsDehoistedField : public BitField<bool, 0, 1> {};
7146 class IsUninitializedField : public BitField<bool, 1, 1> {};
7147 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {};
7148 class ElementsKindField : public BitField<ElementsKind, 3, 5> {};
7150 uint32_t base_offset_;
7151 uint32_t bit_field_;
7156 class HStoreKeyedGeneric FINAL : public HTemplateInstruction<4> {
7158 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreKeyedGeneric, HValue*,
7159 HValue*, HValue*, LanguageMode,
7162 HValue* object() const { return OperandAt(0); }
7163 HValue* key() const { return OperandAt(1); }
7164 HValue* value() const { return OperandAt(2); }
7165 HValue* context() const { return OperandAt(3); }
7166 LanguageMode language_mode() const { return language_mode_; }
7167 InlineCacheState initialization_state() const {
7168 return initialization_state_;
7171 Representation RequiredInputRepresentation(int index) OVERRIDE {
7172 // tagged[tagged] = tagged
7173 return Representation::Tagged();
7176 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7178 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7181 HStoreKeyedGeneric(HValue* context, HValue* object, HValue* key,
7182 HValue* value, LanguageMode language_mode,
7183 InlineCacheState initialization_state)
7184 : language_mode_(language_mode),
7185 initialization_state_(initialization_state) {
7186 SetOperandAt(0, object);
7187 SetOperandAt(1, key);
7188 SetOperandAt(2, value);
7189 SetOperandAt(3, context);
7190 SetAllSideEffects();
7193 LanguageMode language_mode_;
7194 InlineCacheState initialization_state_;
7198 class HTransitionElementsKind FINAL : public HTemplateInstruction<2> {
7200 inline static HTransitionElementsKind* New(Isolate* isolate, Zone* zone,
7201 HValue* context, HValue* object,
7202 Handle<Map> original_map,
7203 Handle<Map> transitioned_map) {
7204 return new(zone) HTransitionElementsKind(context, object,
7205 original_map, transitioned_map);
7208 Representation RequiredInputRepresentation(int index) OVERRIDE {
7209 return Representation::Tagged();
7212 HValue* object() const { return OperandAt(0); }
7213 HValue* context() const { return OperandAt(1); }
7214 Unique<Map> original_map() const { return original_map_; }
7215 Unique<Map> transitioned_map() const { return transitioned_map_; }
7216 ElementsKind from_kind() const {
7217 return FromElementsKindField::decode(bit_field_);
7219 ElementsKind to_kind() const {
7220 return ToElementsKindField::decode(bit_field_);
7222 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
7224 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7226 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7229 bool DataEquals(HValue* other) OVERRIDE {
7230 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7231 return original_map_ == instr->original_map_ &&
7232 transitioned_map_ == instr->transitioned_map_;
7235 int RedefinedOperandIndex() OVERRIDE { return 0; }
7238 HTransitionElementsKind(HValue* context, HValue* object,
7239 Handle<Map> original_map,
7240 Handle<Map> transitioned_map)
7241 : original_map_(Unique<Map>(original_map)),
7242 transitioned_map_(Unique<Map>(transitioned_map)),
7244 FromElementsKindField::encode(original_map->elements_kind()) |
7245 ToElementsKindField::encode(transitioned_map->elements_kind()) |
7246 MapIsStableField::encode(transitioned_map->is_stable())) {
7247 SetOperandAt(0, object);
7248 SetOperandAt(1, context);
7250 SetChangesFlag(kElementsKind);
7251 if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) {
7252 SetChangesFlag(kElementsPointer);
7253 SetChangesFlag(kNewSpacePromotion);
7255 set_representation(Representation::Tagged());
7258 class FromElementsKindField : public BitField<ElementsKind, 0, 5> {};
7259 class ToElementsKindField : public BitField<ElementsKind, 5, 5> {};
7260 class MapIsStableField : public BitField<bool, 10, 1> {};
7262 Unique<Map> original_map_;
7263 Unique<Map> transitioned_map_;
7264 uint32_t bit_field_;
7268 class HStringAdd FINAL : public HBinaryOperation {
7270 static HInstruction* New(
7271 Isolate* isolate, Zone* zone, HValue* context, HValue* left,
7272 HValue* right, PretenureFlag pretenure_flag = NOT_TENURED,
7273 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7274 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null());
7276 StringAddFlags flags() const { return flags_; }
7277 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7279 Representation RequiredInputRepresentation(int index) OVERRIDE {
7280 return Representation::Tagged();
7283 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7285 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7288 bool DataEquals(HValue* other) OVERRIDE {
7289 return flags_ == HStringAdd::cast(other)->flags_ &&
7290 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7294 HStringAdd(HValue* context,
7297 PretenureFlag pretenure_flag,
7298 StringAddFlags flags,
7299 Handle<AllocationSite> allocation_site)
7300 : HBinaryOperation(context, left, right, HType::String()),
7301 flags_(flags), pretenure_flag_(pretenure_flag) {
7302 set_representation(Representation::Tagged());
7304 SetDependsOnFlag(kMaps);
7305 SetChangesFlag(kNewSpacePromotion);
7306 if (FLAG_trace_pretenuring) {
7307 PrintF("HStringAdd with AllocationSite %p %s\n",
7308 allocation_site.is_null()
7309 ? static_cast<void*>(NULL)
7310 : static_cast<void*>(*allocation_site),
7311 pretenure_flag == TENURED ? "tenured" : "not tenured");
7315 // No side-effects except possible allocation:
7316 bool IsDeletable() const OVERRIDE { return true; }
7318 const StringAddFlags flags_;
7319 const PretenureFlag pretenure_flag_;
7323 class HStringCharCodeAt FINAL : public HTemplateInstruction<3> {
7325 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7329 Representation RequiredInputRepresentation(int index) OVERRIDE {
7330 // The index is supposed to be Integer32.
7332 ? Representation::Integer32()
7333 : Representation::Tagged();
7336 HValue* context() const { return OperandAt(0); }
7337 HValue* string() const { return OperandAt(1); }
7338 HValue* index() const { return OperandAt(2); }
7340 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7343 bool DataEquals(HValue* other) OVERRIDE { return true; }
7345 Range* InferRange(Zone* zone) OVERRIDE {
7346 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7350 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7351 SetOperandAt(0, context);
7352 SetOperandAt(1, string);
7353 SetOperandAt(2, index);
7354 set_representation(Representation::Integer32());
7356 SetDependsOnFlag(kMaps);
7357 SetDependsOnFlag(kStringChars);
7358 SetChangesFlag(kNewSpacePromotion);
7361 // No side effects: runtime function assumes string + number inputs.
7362 bool IsDeletable() const OVERRIDE { return true; }
7366 class HStringCharFromCode FINAL : public HTemplateInstruction<2> {
7368 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7371 Representation RequiredInputRepresentation(int index) OVERRIDE {
7373 ? Representation::Tagged()
7374 : Representation::Integer32();
7377 HValue* context() const { return OperandAt(0); }
7378 HValue* value() const { return OperandAt(1); }
7380 bool DataEquals(HValue* other) OVERRIDE { return true; }
7382 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7385 HStringCharFromCode(HValue* context, HValue* char_code)
7386 : HTemplateInstruction<2>(HType::String()) {
7387 SetOperandAt(0, context);
7388 SetOperandAt(1, char_code);
7389 set_representation(Representation::Tagged());
7391 SetChangesFlag(kNewSpacePromotion);
7394 bool IsDeletable() const OVERRIDE {
7395 return !value()->ToNumberCanBeObserved();
7401 class HMaterializedLiteral : public HTemplateInstruction<V> {
7403 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7404 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7405 this->set_representation(Representation::Tagged());
7408 HMaterializedLiteral<V>(int index, int depth)
7409 : literal_index_(index), depth_(depth),
7410 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7411 this->set_representation(Representation::Tagged());
7414 int literal_index() const { return literal_index_; }
7415 int depth() const { return depth_; }
7416 AllocationSiteMode allocation_site_mode() const {
7417 return allocation_site_mode_;
7421 bool IsDeletable() const FINAL { return true; }
7425 AllocationSiteMode allocation_site_mode_;
7429 class HRegExpLiteral FINAL : public HMaterializedLiteral<1> {
7431 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7437 HValue* context() { return OperandAt(0); }
7438 Handle<FixedArray> literals() { return literals_; }
7439 Handle<String> pattern() { return pattern_; }
7440 Handle<String> flags() { return flags_; }
7442 Representation RequiredInputRepresentation(int index) OVERRIDE {
7443 return Representation::Tagged();
7446 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7449 HRegExpLiteral(HValue* context,
7450 Handle<FixedArray> literals,
7451 Handle<String> pattern,
7452 Handle<String> flags,
7454 : HMaterializedLiteral<1>(literal_index, 0),
7455 literals_(literals),
7458 SetOperandAt(0, context);
7459 SetAllSideEffects();
7460 set_type(HType::JSObject());
7463 Handle<FixedArray> literals_;
7464 Handle<String> pattern_;
7465 Handle<String> flags_;
7469 class HFunctionLiteral FINAL : public HTemplateInstruction<1> {
7471 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7472 Handle<SharedFunctionInfo>,
7474 HValue* context() { return OperandAt(0); }
7476 Representation RequiredInputRepresentation(int index) OVERRIDE {
7477 return Representation::Tagged();
7480 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7482 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7483 bool pretenure() const { return PretenureField::decode(bit_field_); }
7484 bool has_no_literals() const {
7485 return HasNoLiteralsField::decode(bit_field_);
7487 FunctionKind kind() const { return FunctionKindField::decode(bit_field_); }
7488 LanguageMode language_mode() const {
7489 return LanguageModeField::decode(bit_field_);
7493 HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> shared,
7495 : HTemplateInstruction<1>(HType::JSObject()),
7496 shared_info_(shared),
7497 bit_field_(FunctionKindField::encode(shared->kind()) |
7498 PretenureField::encode(pretenure) |
7499 HasNoLiteralsField::encode(shared->num_literals() == 0) |
7500 LanguageModeField::encode(shared->language_mode())) {
7501 SetOperandAt(0, context);
7502 set_representation(Representation::Tagged());
7503 SetChangesFlag(kNewSpacePromotion);
7506 bool IsDeletable() const OVERRIDE { return true; }
7508 class FunctionKindField : public BitField<FunctionKind, 0, 8> {};
7509 class PretenureField : public BitField<bool, 8, 1> {};
7510 class HasNoLiteralsField : public BitField<bool, 9, 1> {};
7511 STATIC_ASSERT(LANGUAGE_END == 3);
7512 class LanguageModeField : public BitField<LanguageMode, 10, 2> {};
7514 Handle<SharedFunctionInfo> shared_info_;
7515 uint32_t bit_field_;
7519 class HTypeof FINAL : public HTemplateInstruction<2> {
7521 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7523 HValue* context() const { return OperandAt(0); }
7524 HValue* value() const { return OperandAt(1); }
7526 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7528 Representation RequiredInputRepresentation(int index) OVERRIDE {
7529 return Representation::Tagged();
7532 DECLARE_CONCRETE_INSTRUCTION(Typeof)
7535 explicit HTypeof(HValue* context, HValue* value) {
7536 SetOperandAt(0, context);
7537 SetOperandAt(1, value);
7538 set_representation(Representation::Tagged());
7541 bool IsDeletable() const OVERRIDE { return true; }
7545 class HTrapAllocationMemento FINAL : public HTemplateInstruction<1> {
7547 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7549 Representation RequiredInputRepresentation(int index) OVERRIDE {
7550 return Representation::Tagged();
7553 HValue* object() { return OperandAt(0); }
7555 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7558 explicit HTrapAllocationMemento(HValue* obj) {
7559 SetOperandAt(0, obj);
7564 class HToFastProperties FINAL : public HUnaryOperation {
7566 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7568 Representation RequiredInputRepresentation(int index) OVERRIDE {
7569 return Representation::Tagged();
7572 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7575 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7576 set_representation(Representation::Tagged());
7577 SetChangesFlag(kNewSpacePromotion);
7579 // This instruction is not marked as kChangesMaps, but does
7580 // change the map of the input operand. Use it only when creating
7581 // object literals via a runtime call.
7582 DCHECK(value->IsCallRuntime());
7584 const Runtime::Function* function = HCallRuntime::cast(value)->function();
7585 DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7589 bool IsDeletable() const OVERRIDE { return true; }
7593 class HDateField FINAL : public HUnaryOperation {
7595 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7597 Smi* index() const { return index_; }
7599 Representation RequiredInputRepresentation(int index) OVERRIDE {
7600 return Representation::Tagged();
7603 DECLARE_CONCRETE_INSTRUCTION(DateField)
7606 HDateField(HValue* date, Smi* index)
7607 : HUnaryOperation(date), index_(index) {
7608 set_representation(Representation::Tagged());
7615 class HSeqStringGetChar FINAL : public HTemplateInstruction<2> {
7617 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
7618 String::Encoding encoding, HValue* string,
7621 Representation RequiredInputRepresentation(int index) OVERRIDE {
7622 return (index == 0) ? Representation::Tagged()
7623 : Representation::Integer32();
7626 String::Encoding encoding() const { return encoding_; }
7627 HValue* string() const { return OperandAt(0); }
7628 HValue* index() const { return OperandAt(1); }
7630 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7633 bool DataEquals(HValue* other) OVERRIDE {
7634 return encoding() == HSeqStringGetChar::cast(other)->encoding();
7637 Range* InferRange(Zone* zone) OVERRIDE {
7638 if (encoding() == String::ONE_BYTE_ENCODING) {
7639 return new(zone) Range(0, String::kMaxOneByteCharCode);
7641 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7642 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7647 HSeqStringGetChar(String::Encoding encoding,
7649 HValue* index) : encoding_(encoding) {
7650 SetOperandAt(0, string);
7651 SetOperandAt(1, index);
7652 set_representation(Representation::Integer32());
7654 SetDependsOnFlag(kStringChars);
7657 bool IsDeletable() const OVERRIDE { return true; }
7659 String::Encoding encoding_;
7663 class HSeqStringSetChar FINAL : public HTemplateInstruction<4> {
7665 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7666 HSeqStringSetChar, String::Encoding,
7667 HValue*, HValue*, HValue*);
7669 String::Encoding encoding() { return encoding_; }
7670 HValue* context() { return OperandAt(0); }
7671 HValue* string() { return OperandAt(1); }
7672 HValue* index() { return OperandAt(2); }
7673 HValue* value() { return OperandAt(3); }
7675 Representation RequiredInputRepresentation(int index) OVERRIDE {
7676 return (index <= 1) ? Representation::Tagged()
7677 : Representation::Integer32();
7680 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7683 HSeqStringSetChar(HValue* context,
7684 String::Encoding encoding,
7687 HValue* value) : encoding_(encoding) {
7688 SetOperandAt(0, context);
7689 SetOperandAt(1, string);
7690 SetOperandAt(2, index);
7691 SetOperandAt(3, value);
7692 set_representation(Representation::Tagged());
7693 SetChangesFlag(kStringChars);
7696 String::Encoding encoding_;
7700 class HCheckMapValue FINAL : public HTemplateInstruction<2> {
7702 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7704 Representation RequiredInputRepresentation(int index) OVERRIDE {
7705 return Representation::Tagged();
7708 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7710 HType CalculateInferredType() OVERRIDE {
7711 if (value()->type().IsHeapObject()) return value()->type();
7712 return HType::HeapObject();
7715 HValue* value() const { return OperandAt(0); }
7716 HValue* map() const { return OperandAt(1); }
7718 HValue* Canonicalize() OVERRIDE;
7720 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7723 int RedefinedOperandIndex() OVERRIDE { return 0; }
7725 bool DataEquals(HValue* other) OVERRIDE { return true; }
7728 HCheckMapValue(HValue* value, HValue* map)
7729 : HTemplateInstruction<2>(HType::HeapObject()) {
7730 SetOperandAt(0, value);
7731 SetOperandAt(1, map);
7732 set_representation(Representation::Tagged());
7734 SetDependsOnFlag(kMaps);
7735 SetDependsOnFlag(kElementsKind);
7740 class HForInPrepareMap FINAL : public HTemplateInstruction<2> {
7742 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7744 Representation RequiredInputRepresentation(int index) OVERRIDE {
7745 return Representation::Tagged();
7748 HValue* context() const { return OperandAt(0); }
7749 HValue* enumerable() const { return OperandAt(1); }
7751 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7753 HType CalculateInferredType() OVERRIDE { return HType::Tagged(); }
7755 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7758 HForInPrepareMap(HValue* context,
7760 SetOperandAt(0, context);
7761 SetOperandAt(1, object);
7762 set_representation(Representation::Tagged());
7763 SetAllSideEffects();
7768 class HForInCacheArray FINAL : public HTemplateInstruction<2> {
7770 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7772 Representation RequiredInputRepresentation(int index) OVERRIDE {
7773 return Representation::Tagged();
7776 HValue* enumerable() const { return OperandAt(0); }
7777 HValue* map() const { return OperandAt(1); }
7778 int idx() const { return idx_; }
7780 HForInCacheArray* index_cache() {
7781 return index_cache_;
7784 void set_index_cache(HForInCacheArray* index_cache) {
7785 index_cache_ = index_cache;
7788 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7790 HType CalculateInferredType() OVERRIDE { return HType::Tagged(); }
7792 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7795 HForInCacheArray(HValue* enumerable,
7797 int idx) : idx_(idx) {
7798 SetOperandAt(0, enumerable);
7799 SetOperandAt(1, keys);
7800 set_representation(Representation::Tagged());
7804 HForInCacheArray* index_cache_;
7808 class HLoadFieldByIndex FINAL : public HTemplateInstruction<2> {
7810 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7812 HLoadFieldByIndex(HValue* object,
7814 SetOperandAt(0, object);
7815 SetOperandAt(1, index);
7816 SetChangesFlag(kNewSpacePromotion);
7817 set_representation(Representation::Tagged());
7820 Representation RequiredInputRepresentation(int index) OVERRIDE {
7822 return Representation::Smi();
7824 return Representation::Tagged();
7828 HValue* object() const { return OperandAt(0); }
7829 HValue* index() const { return OperandAt(1); }
7831 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7833 HType CalculateInferredType() OVERRIDE { return HType::Tagged(); }
7835 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
7838 bool IsDeletable() const OVERRIDE { return true; }
7842 class HStoreFrameContext: public HUnaryOperation {
7844 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
7846 HValue* context() { return OperandAt(0); }
7848 Representation RequiredInputRepresentation(int index) OVERRIDE {
7849 return Representation::Tagged();
7852 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
7854 explicit HStoreFrameContext(HValue* context)
7855 : HUnaryOperation(context) {
7856 set_representation(Representation::Tagged());
7857 SetChangesFlag(kContextSlots);
7862 class HAllocateBlockContext: public HTemplateInstruction<2> {
7864 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
7865 HValue*, Handle<ScopeInfo>);
7866 HValue* context() const { return OperandAt(0); }
7867 HValue* function() const { return OperandAt(1); }
7868 Handle<ScopeInfo> scope_info() const { return scope_info_; }
7870 Representation RequiredInputRepresentation(int index) OVERRIDE {
7871 return Representation::Tagged();
7874 std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
7876 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
7879 HAllocateBlockContext(HValue* context,
7881 Handle<ScopeInfo> scope_info)
7882 : scope_info_(scope_info) {
7883 SetOperandAt(0, context);
7884 SetOperandAt(1, function);
7885 set_representation(Representation::Tagged());
7888 Handle<ScopeInfo> scope_info_;
7893 #undef DECLARE_INSTRUCTION
7894 #undef DECLARE_CONCRETE_INSTRUCTION
7896 } } // namespace v8::internal
7898 #endif // V8_HYDROGEN_INSTRUCTIONS_H_