Upstream version 9.38.207.0
[platform/framework/web/crosswalk.git] / src / v8 / src / hydrogen-instructions.h
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.
4
5 #ifndef V8_HYDROGEN_INSTRUCTIONS_H_
6 #define V8_HYDROGEN_INSTRUCTIONS_H_
7
8 #include "src/v8.h"
9
10 #include "src/allocation.h"
11 #include "src/code-stubs.h"
12 #include "src/conversions.h"
13 #include "src/data-flow.h"
14 #include "src/deoptimizer.h"
15 #include "src/feedback-slots.h"
16 #include "src/hydrogen-types.h"
17 #include "src/small-pointer-list.h"
18 #include "src/unique.h"
19 #include "src/utils.h"
20 #include "src/zone.h"
21
22 namespace v8 {
23 namespace internal {
24
25 // Forward declarations.
26 struct ChangesOf;
27 class HBasicBlock;
28 class HDiv;
29 class HEnvironment;
30 class HInferRepresentationPhase;
31 class HInstruction;
32 class HLoopInformation;
33 class HStoreNamedField;
34 class HValue;
35 class LInstruction;
36 class LChunkBuilder;
37 class OStream;
38
39 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V)  \
40   V(ArithmeticBinaryOperation)                 \
41   V(BinaryOperation)                           \
42   V(BitwiseBinaryOperation)                    \
43   V(ControlInstruction)                        \
44   V(Instruction)                               \
45
46
47 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V)  \
48   V(AbnormalExit)                              \
49   V(AccessArgumentsAt)                         \
50   V(Add)                                       \
51   V(AllocateBlockContext)                      \
52   V(Allocate)                                  \
53   V(ApplyArguments)                            \
54   V(ArgumentsElements)                         \
55   V(ArgumentsLength)                           \
56   V(ArgumentsObject)                           \
57   V(Bitwise)                                   \
58   V(BlockEntry)                                \
59   V(BoundsCheck)                               \
60   V(BoundsCheckBaseIndexInformation)           \
61   V(Branch)                                    \
62   V(CallWithDescriptor)                        \
63   V(CallJSFunction)                            \
64   V(CallFunction)                              \
65   V(CallNew)                                   \
66   V(CallNewArray)                              \
67   V(CallRuntime)                               \
68   V(CallStub)                                  \
69   V(CapturedObject)                            \
70   V(Change)                                    \
71   V(CheckHeapObject)                           \
72   V(CheckInstanceType)                         \
73   V(CheckMaps)                                 \
74   V(CheckMapValue)                             \
75   V(CheckSmi)                                  \
76   V(CheckValue)                                \
77   V(ClampToUint8)                              \
78   V(ClassOfTestAndBranch)                      \
79   V(CompareNumericAndBranch)                   \
80   V(CompareHoleAndBranch)                      \
81   V(CompareGeneric)                            \
82   V(CompareMinusZeroAndBranch)                 \
83   V(CompareObjectEqAndBranch)                  \
84   V(CompareMap)                                \
85   V(Constant)                                  \
86   V(ConstructDouble)                           \
87   V(Context)                                   \
88   V(DateField)                                 \
89   V(DebugBreak)                                \
90   V(DeclareGlobals)                            \
91   V(Deoptimize)                                \
92   V(Div)                                       \
93   V(DoubleBits)                                \
94   V(DummyUse)                                  \
95   V(EnterInlined)                              \
96   V(EnvironmentMarker)                         \
97   V(ForceRepresentation)                       \
98   V(ForInCacheArray)                           \
99   V(ForInPrepareMap)                           \
100   V(FunctionLiteral)                           \
101   V(GetCachedArrayIndex)                       \
102   V(Goto)                                      \
103   V(HasCachedArrayIndexAndBranch)              \
104   V(HasInstanceTypeAndBranch)                  \
105   V(InnerAllocatedObject)                      \
106   V(InstanceOf)                                \
107   V(InstanceOfKnownGlobal)                     \
108   V(InvokeFunction)                            \
109   V(IsConstructCallAndBranch)                  \
110   V(IsObjectAndBranch)                         \
111   V(IsStringAndBranch)                         \
112   V(IsSmiAndBranch)                            \
113   V(IsUndetectableAndBranch)                   \
114   V(LeaveInlined)                              \
115   V(LoadContextSlot)                           \
116   V(LoadFieldByIndex)                          \
117   V(LoadFunctionPrototype)                     \
118   V(LoadGlobalCell)                            \
119   V(LoadGlobalGeneric)                         \
120   V(LoadKeyed)                                 \
121   V(LoadKeyedGeneric)                          \
122   V(LoadNamedField)                            \
123   V(LoadNamedGeneric)                          \
124   V(LoadRoot)                                  \
125   V(MapEnumLength)                             \
126   V(MathFloorOfDiv)                            \
127   V(MathMinMax)                                \
128   V(Mod)                                       \
129   V(Mul)                                       \
130   V(OsrEntry)                                  \
131   V(Parameter)                                 \
132   V(Power)                                     \
133   V(PushArguments)                             \
134   V(RegExpLiteral)                             \
135   V(Return)                                    \
136   V(Ror)                                       \
137   V(Sar)                                       \
138   V(SeqStringGetChar)                          \
139   V(SeqStringSetChar)                          \
140   V(Shl)                                       \
141   V(Shr)                                       \
142   V(Simulate)                                  \
143   V(StackCheck)                                \
144   V(StoreCodeEntry)                            \
145   V(StoreContextSlot)                          \
146   V(StoreFrameContext)                         \
147   V(StoreGlobalCell)                           \
148   V(StoreKeyed)                                \
149   V(StoreKeyedGeneric)                         \
150   V(StoreNamedField)                           \
151   V(StoreNamedGeneric)                         \
152   V(StringAdd)                                 \
153   V(StringCharCodeAt)                          \
154   V(StringCharFromCode)                        \
155   V(StringCompareAndBranch)                    \
156   V(Sub)                                       \
157   V(ThisFunction)                              \
158   V(ToFastProperties)                          \
159   V(TransitionElementsKind)                    \
160   V(TrapAllocationMemento)                     \
161   V(Typeof)                                    \
162   V(TypeofIsAndBranch)                         \
163   V(UnaryMathOperation)                        \
164   V(NullarySIMDOperation)                      \
165   V(UnarySIMDOperation)                        \
166   V(BinarySIMDOperation)                       \
167   V(TernarySIMDOperation)                      \
168   V(QuarternarySIMDOperation)                  \
169   V(UnknownOSRValue)                           \
170   V(UseConst)                                  \
171   V(WrapReceiver)
172
173 #define GVN_TRACKED_FLAG_LIST(V)               \
174   V(NewSpacePromotion)
175
176 #define GVN_UNTRACKED_FLAG_LIST(V)             \
177   V(ArrayElements)                             \
178   V(ArrayLengths)                              \
179   V(StringLengths)                             \
180   V(BackingStoreFields)                        \
181   V(Calls)                                     \
182   V(ContextSlots)                              \
183   V(DoubleArrayElements)                       \
184   V(DoubleFields)                              \
185   V(ElementsKind)                              \
186   V(ElementsPointer)                           \
187   V(GlobalVars)                                \
188   V(InobjectFields)                            \
189   V(Maps)                                      \
190   V(OsrEntries)                                \
191   V(ExternalMemory)                            \
192   V(StringChars)                               \
193   V(TypedArrayElements)
194
195
196 #define DECLARE_ABSTRACT_INSTRUCTION(type)                              \
197   virtual bool Is##type() const V8_FINAL V8_OVERRIDE { return true; }   \
198   static H##type* cast(HValue* value) {                                 \
199     DCHECK(value->Is##type());                                          \
200     return reinterpret_cast<H##type*>(value);                           \
201   }
202
203
204 #define DECLARE_CONCRETE_INSTRUCTION(type)              \
205   virtual LInstruction* CompileToLithium(               \
206      LChunkBuilder* builder) V8_FINAL V8_OVERRIDE;      \
207   static H##type* cast(HValue* value) {                 \
208     DCHECK(value->Is##type());                          \
209     return reinterpret_cast<H##type*>(value);           \
210   }                                                     \
211   virtual Opcode opcode() const V8_FINAL V8_OVERRIDE {  \
212     return HValue::k##type;                             \
213   }
214
215
216 enum PropertyAccessType { LOAD, STORE };
217
218
219 class Range V8_FINAL : public ZoneObject {
220  public:
221   Range()
222       : lower_(kMinInt),
223         upper_(kMaxInt),
224         next_(NULL),
225         can_be_minus_zero_(false) { }
226
227   Range(int32_t lower, int32_t upper)
228       : lower_(lower),
229         upper_(upper),
230         next_(NULL),
231         can_be_minus_zero_(false) { }
232
233   int32_t upper() const { return upper_; }
234   int32_t lower() const { return lower_; }
235   Range* next() const { return next_; }
236   Range* CopyClearLower(Zone* zone) const {
237     return new(zone) Range(kMinInt, upper_);
238   }
239   Range* CopyClearUpper(Zone* zone) const {
240     return new(zone) Range(lower_, kMaxInt);
241   }
242   Range* Copy(Zone* zone) const {
243     Range* result = new(zone) Range(lower_, upper_);
244     result->set_can_be_minus_zero(CanBeMinusZero());
245     return result;
246   }
247   int32_t Mask() const;
248   void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
249   bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
250   bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
251   bool CanBeNegative() const { return lower_ < 0; }
252   bool CanBePositive() const { return upper_ > 0; }
253   bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
254   bool IsMostGeneric() const {
255     return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
256   }
257   bool IsInSmiRange() const {
258     return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
259   }
260   void ClampToSmi() {
261     lower_ = Max(lower_, Smi::kMinValue);
262     upper_ = Min(upper_, Smi::kMaxValue);
263   }
264   void KeepOrder();
265 #ifdef DEBUG
266   void Verify() const;
267 #endif
268
269   void StackUpon(Range* other) {
270     Intersect(other);
271     next_ = other;
272   }
273
274   void Intersect(Range* other);
275   void Union(Range* other);
276   void CombinedMax(Range* other);
277   void CombinedMin(Range* other);
278
279   void AddConstant(int32_t value);
280   void Sar(int32_t value);
281   void Shl(int32_t value);
282   bool AddAndCheckOverflow(const Representation& r, Range* other);
283   bool SubAndCheckOverflow(const Representation& r, Range* other);
284   bool MulAndCheckOverflow(const Representation& r, Range* other);
285
286  private:
287   int32_t lower_;
288   int32_t upper_;
289   Range* next_;
290   bool can_be_minus_zero_;
291 };
292
293
294 class HUseListNode: public ZoneObject {
295  public:
296   HUseListNode(HValue* value, int index, HUseListNode* tail)
297       : tail_(tail), value_(value), index_(index) {
298   }
299
300   HUseListNode* tail();
301   HValue* value() const { return value_; }
302   int index() const { return index_; }
303
304   void set_tail(HUseListNode* list) { tail_ = list; }
305
306 #ifdef DEBUG
307   void Zap() {
308     tail_ = reinterpret_cast<HUseListNode*>(1);
309     value_ = NULL;
310     index_ = -1;
311   }
312 #endif
313
314  private:
315   HUseListNode* tail_;
316   HValue* value_;
317   int index_;
318 };
319
320
321 // We reuse use list nodes behind the scenes as uses are added and deleted.
322 // This class is the safe way to iterate uses while deleting them.
323 class HUseIterator V8_FINAL BASE_EMBEDDED {
324  public:
325   bool Done() { return current_ == NULL; }
326   void Advance();
327
328   HValue* value() {
329     DCHECK(!Done());
330     return value_;
331   }
332
333   int index() {
334     DCHECK(!Done());
335     return index_;
336   }
337
338  private:
339   explicit HUseIterator(HUseListNode* head);
340
341   HUseListNode* current_;
342   HUseListNode* next_;
343   HValue* value_;
344   int index_;
345
346   friend class HValue;
347 };
348
349
350 // All tracked flags should appear before untracked ones.
351 enum GVNFlag {
352   // Declare global value numbering flags.
353 #define DECLARE_FLAG(Type) k##Type,
354   GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
355   GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
356 #undef DECLARE_FLAG
357 #define COUNT_FLAG(Type) + 1
358   kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
359   kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
360 #undef COUNT_FLAG
361   kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
362 };
363
364
365 static inline GVNFlag GVNFlagFromInt(int i) {
366   DCHECK(i >= 0);
367   DCHECK(i < kNumberOfFlags);
368   return static_cast<GVNFlag>(i);
369 }
370
371
372 class DecompositionResult V8_FINAL BASE_EMBEDDED {
373  public:
374   DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
375
376   HValue* base() { return base_; }
377   int offset() { return offset_; }
378   int scale() { return scale_; }
379
380   bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
381     if (base_ == NULL) {
382       base_ = other_base;
383       offset_ = other_offset;
384       scale_ = other_scale;
385       return true;
386     } else {
387       if (scale_ == 0) {
388         base_ = other_base;
389         offset_ += other_offset;
390         scale_ = other_scale;
391         return true;
392       } else {
393         return false;
394       }
395     }
396   }
397
398   void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
399     swap(&base_, other_base);
400     swap(&offset_, other_offset);
401     swap(&scale_, other_scale);
402   }
403
404  private:
405   template <class T> void swap(T* a, T* b) {
406     T c(*a);
407     *a = *b;
408     *b = c;
409   }
410
411   HValue* base_;
412   int offset_;
413   int scale_;
414 };
415
416
417 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
418
419
420 // This class encapsulates encoding and decoding of sources positions from
421 // which hydrogen values originated.
422 // When FLAG_track_hydrogen_positions is set this object encodes the
423 // identifier of the inlining and absolute offset from the start of the
424 // inlined function.
425 // When the flag is not set we simply track absolute offset from the
426 // script start.
427 class HSourcePosition {
428  public:
429   HSourcePosition(const HSourcePosition& other) : value_(other.value_) { }
430
431   static HSourcePosition Unknown() {
432     return HSourcePosition(RelocInfo::kNoPosition);
433   }
434
435   bool IsUnknown() const { return value_ == RelocInfo::kNoPosition; }
436
437   int position() const { return PositionField::decode(value_); }
438   void set_position(int position) {
439     if (FLAG_hydrogen_track_positions) {
440       value_ = static_cast<int>(PositionField::update(value_, position));
441     } else {
442       value_ = position;
443     }
444   }
445
446   int inlining_id() const { return InliningIdField::decode(value_); }
447   void set_inlining_id(int inlining_id) {
448     if (FLAG_hydrogen_track_positions) {
449       value_ = static_cast<int>(InliningIdField::update(value_, inlining_id));
450     }
451   }
452
453   int raw() const { return value_; }
454
455  private:
456   typedef BitField<int, 0, 9> InliningIdField;
457
458   // Offset from the start of the inlined function.
459   typedef BitField<int, 9, 23> PositionField;
460
461   // On HPositionInfo can use this constructor.
462   explicit HSourcePosition(int value) : value_(value) { }
463
464   friend class HPositionInfo;
465
466   // If FLAG_hydrogen_track_positions is set contains bitfields InliningIdField
467   // and PositionField.
468   // Otherwise contains absolute offset from the script start.
469   int value_;
470 };
471
472
473 OStream& operator<<(OStream& os, const HSourcePosition& p);
474
475
476 class HValue : public ZoneObject {
477  public:
478   static const int kNoNumber = -1;
479
480   enum Flag {
481     kFlexibleRepresentation,
482     kCannotBeTagged,
483     // Participate in Global Value Numbering, i.e. elimination of
484     // unnecessary recomputations. If an instruction sets this flag, it must
485     // implement DataEquals(), which will be used to determine if other
486     // occurrences of the instruction are indeed the same.
487     kUseGVN,
488     // Track instructions that are dominating side effects. If an instruction
489     // sets this flag, it must implement HandleSideEffectDominator() and should
490     // indicate which side effects to track by setting GVN flags.
491     kTrackSideEffectDominators,
492     kCanOverflow,
493     kBailoutOnMinusZero,
494     kCanBeDivByZero,
495     kLeftCanBeMinInt,
496     kLeftCanBeNegative,
497     kLeftCanBePositive,
498     kAllowUndefinedAsNaN,
499     kIsArguments,
500     kTruncatingToInt32,
501     kAllUsesTruncatingToInt32,
502     kTruncatingToSmi,
503     kAllUsesTruncatingToSmi,
504     // Set after an instruction is killed.
505     kIsDead,
506     // Instructions that are allowed to produce full range unsigned integer
507     // values are marked with kUint32 flag. If arithmetic shift or a load from
508     // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
509     // it will deoptimize if result does not fit into signed integer range.
510     // HGraph::ComputeSafeUint32Operations is responsible for setting this
511     // flag.
512     kUint32,
513     kHasNoObservableSideEffects,
514     // Indicates an instruction shouldn't be replaced by optimization, this flag
515     // is useful to set in cases where recomputing a value is cheaper than
516     // extending the value's live range and spilling it.
517     kCantBeReplaced,
518     // Indicates the instruction is live during dead code elimination.
519     kIsLive,
520
521     // HEnvironmentMarkers are deleted before dead code
522     // elimination takes place, so they can repurpose the kIsLive flag:
523     kEndsLiveRange = kIsLive,
524
525     // TODO(everyone): Don't forget to update this!
526     kLastFlag = kIsLive
527   };
528
529   STATIC_ASSERT(kLastFlag < kBitsPerInt);
530
531   static HValue* cast(HValue* value) { return value; }
532
533   enum Opcode {
534     // Declare a unique enum value for each hydrogen instruction.
535   #define DECLARE_OPCODE(type) k##type,
536     HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
537     kPhi
538   #undef DECLARE_OPCODE
539   };
540   virtual Opcode opcode() const = 0;
541
542   // Declare a non-virtual predicates for each concrete HInstruction or HValue.
543   #define DECLARE_PREDICATE(type) \
544     bool Is##type() const { return opcode() == k##type; }
545     HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
546   #undef DECLARE_PREDICATE
547     bool IsPhi() const { return opcode() == kPhi; }
548
549   // Declare virtual predicates for abstract HInstruction or HValue
550   #define DECLARE_PREDICATE(type) \
551     virtual bool Is##type() const { return false; }
552     HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
553   #undef DECLARE_PREDICATE
554
555   bool IsBitwiseBinaryShift() {
556     return IsShl() || IsShr() || IsSar();
557   }
558
559   explicit HValue(HType type = HType::Tagged())
560       : block_(NULL),
561         id_(kNoNumber),
562         type_(type),
563         use_list_(NULL),
564         range_(NULL),
565 #ifdef DEBUG
566         range_poisoned_(false),
567 #endif
568         flags_(0) {}
569   virtual ~HValue() {}
570
571   virtual HSourcePosition position() const {
572     return HSourcePosition::Unknown();
573   }
574   virtual HSourcePosition operand_position(int index) const {
575     return position();
576   }
577
578   HBasicBlock* block() const { return block_; }
579   void SetBlock(HBasicBlock* block);
580
581   // Note: Never call this method for an unlinked value.
582   Isolate* isolate() const;
583
584   int id() const { return id_; }
585   void set_id(int id) { id_ = id; }
586
587   HUseIterator uses() const { return HUseIterator(use_list_); }
588
589   virtual bool EmitAtUses() { return false; }
590
591   Representation representation() const { return representation_; }
592   void ChangeRepresentation(Representation r) {
593     DCHECK(CheckFlag(kFlexibleRepresentation));
594     DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
595     RepresentationChanged(r);
596     representation_ = r;
597     if (r.IsTagged()) {
598       // Tagged is the bottom of the lattice, don't go any further.
599       ClearFlag(kFlexibleRepresentation);
600     }
601   }
602   virtual void AssumeRepresentation(Representation r);
603
604   virtual Representation KnownOptimalRepresentation() {
605     Representation r = representation();
606     if (r.IsTagged()) {
607       HType t = type();
608       if (t.IsSmi()) return Representation::Smi();
609       if (t.IsHeapNumber()) return Representation::Double();
610       if (t.IsFloat32x4()) return Representation::Float32x4();
611       if (t.IsFloat64x2()) return Representation::Float64x2();
612       if (t.IsInt32x4()) return Representation::Int32x4();
613       if (t.IsHeapObject()) return r;
614       return Representation::None();
615     }
616     return r;
617   }
618
619   HType type() const { return type_; }
620   void set_type(HType new_type) {
621     // TODO(ningxin): for SIMD ops, the initial type is None which
622     // hit the following ASSERT.
623     // DCHECK(new_type.IsSubtypeOf(type_));
624     type_ = new_type;
625   }
626
627   // There are HInstructions that do not really change a value, they
628   // only add pieces of information to it (like bounds checks, map checks,
629   // smi checks...).
630   // We call these instructions "informative definitions", or "iDef".
631   // One of the iDef operands is special because it is the value that is
632   // "transferred" to the output, we call it the "redefined operand".
633   // If an HValue is an iDef it must override RedefinedOperandIndex() so that
634   // it does not return kNoRedefinedOperand;
635   static const int kNoRedefinedOperand = -1;
636   virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
637   bool IsInformativeDefinition() {
638     return RedefinedOperandIndex() != kNoRedefinedOperand;
639   }
640   HValue* RedefinedOperand() {
641     int index = RedefinedOperandIndex();
642     return index == kNoRedefinedOperand ? NULL : OperandAt(index);
643   }
644
645   bool CanReplaceWithDummyUses();
646
647   virtual int argument_delta() const { return 0; }
648
649   // A purely informative definition is an idef that will not emit code and
650   // should therefore be removed from the graph in the RestoreActualValues
651   // phase (so that live ranges will be shorter).
652   virtual bool IsPurelyInformativeDefinition() { return false; }
653
654   // This method must always return the original HValue SSA definition,
655   // regardless of any chain of iDefs of this value.
656   HValue* ActualValue() {
657     HValue* value = this;
658     int index;
659     while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
660       value = value->OperandAt(index);
661     }
662     return value;
663   }
664
665   bool IsInteger32Constant();
666   int32_t GetInteger32Constant();
667   bool EqualsInteger32Constant(int32_t value);
668
669   bool IsDefinedAfter(HBasicBlock* other) const;
670
671   // Operands.
672   virtual int OperandCount() const = 0;
673   virtual HValue* OperandAt(int index) const = 0;
674   void SetOperandAt(int index, HValue* value);
675
676   void DeleteAndReplaceWith(HValue* other);
677   void ReplaceAllUsesWith(HValue* other);
678   bool HasNoUses() const { return use_list_ == NULL; }
679   bool HasOneUse() const {
680     return use_list_ != NULL && use_list_->tail() == NULL;
681   }
682   bool HasMultipleUses() const {
683     return use_list_ != NULL && use_list_->tail() != NULL;
684   }
685   int UseCount() const;
686
687   // Mark this HValue as dead and to be removed from other HValues' use lists.
688   void Kill();
689
690   int flags() const { return flags_; }
691   void SetFlag(Flag f) { flags_ |= (1 << f); }
692   void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
693   bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
694   void CopyFlag(Flag f, HValue* other) {
695     if (other->CheckFlag(f)) SetFlag(f);
696   }
697
698   // Returns true if the flag specified is set for all uses, false otherwise.
699   bool CheckUsesForFlag(Flag f) const;
700   // Same as before and the first one without the flag is returned in value.
701   bool CheckUsesForFlag(Flag f, HValue** value) const;
702   // Returns true if the flag specified is set for all uses, and this set
703   // of uses is non-empty.
704   bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
705
706   GVNFlagSet ChangesFlags() const { return changes_flags_; }
707   GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
708   void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
709   void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
710   void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
711   void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
712   bool CheckChangesFlag(GVNFlag f) const {
713     return changes_flags_.Contains(f);
714   }
715   bool CheckDependsOnFlag(GVNFlag f) const {
716     return depends_on_flags_.Contains(f);
717   }
718   void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
719   void ClearAllSideEffects() {
720     changes_flags_.Remove(AllSideEffectsFlagSet());
721   }
722   bool HasSideEffects() const {
723     return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
724   }
725   bool HasObservableSideEffects() const {
726     return !CheckFlag(kHasNoObservableSideEffects) &&
727         changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
728   }
729
730   GVNFlagSet SideEffectFlags() const {
731     GVNFlagSet result = ChangesFlags();
732     result.Intersect(AllSideEffectsFlagSet());
733     return result;
734   }
735
736   GVNFlagSet ObservableChangesFlags() const {
737     GVNFlagSet result = ChangesFlags();
738     result.Intersect(AllObservableSideEffectsFlagSet());
739     return result;
740   }
741
742   Range* range() const {
743     DCHECK(!range_poisoned_);
744     return range_;
745   }
746   bool HasRange() const {
747     DCHECK(!range_poisoned_);
748     return range_ != NULL;
749   }
750 #ifdef DEBUG
751   void PoisonRange() { range_poisoned_ = true; }
752 #endif
753   void AddNewRange(Range* r, Zone* zone);
754   void RemoveLastAddedRange();
755   void ComputeInitialRange(Zone* zone);
756
757   // Escape analysis helpers.
758   virtual bool HasEscapingOperandAt(int index) { return true; }
759   virtual bool HasOutOfBoundsAccess(int size) { return false; }
760
761   // Representation helpers.
762   virtual Representation observed_input_representation(int index) {
763     return Representation::None();
764   }
765   virtual Representation RequiredInputRepresentation(int index) = 0;
766   virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
767
768   // This gives the instruction an opportunity to replace itself with an
769   // instruction that does the same in some better way.  To replace an
770   // instruction with a new one, first add the new instruction to the graph,
771   // then return it.  Return NULL to have the instruction deleted.
772   virtual HValue* Canonicalize() { return this; }
773
774   bool Equals(HValue* other);
775   virtual intptr_t Hashcode();
776
777   // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
778   virtual void FinalizeUniqueness() { }
779
780   // Printing support.
781   virtual OStream& PrintTo(OStream& os) const = 0;  // NOLINT
782
783   const char* Mnemonic() const;
784
785   // Type information helpers.
786   bool HasMonomorphicJSObjectType();
787
788   // TODO(mstarzinger): For now instructions can override this function to
789   // specify statically known types, once HType can convey more information
790   // it should be based on the HType.
791   virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
792
793   // Updated the inferred type of this instruction and returns true if
794   // it has changed.
795   bool UpdateInferredType();
796
797   virtual HType CalculateInferredType();
798
799   // This function must be overridden for instructions which have the
800   // kTrackSideEffectDominators flag set, to track instructions that are
801   // dominating side effects.
802   // It returns true if it removed an instruction which had side effects.
803   virtual bool HandleSideEffectDominator(GVNFlag side_effect,
804                                          HValue* dominator) {
805     UNREACHABLE();
806     return false;
807   }
808
809   // Check if this instruction has some reason that prevents elimination.
810   bool CannotBeEliminated() const {
811     return HasObservableSideEffects() || !IsDeletable();
812   }
813
814 #ifdef DEBUG
815   virtual void Verify() = 0;
816 #endif
817
818   virtual bool TryDecompose(DecompositionResult* decomposition) {
819     if (RedefinedOperand() != NULL) {
820       return RedefinedOperand()->TryDecompose(decomposition);
821     } else {
822       return false;
823     }
824   }
825
826   // Returns true conservatively if the program might be able to observe a
827   // ToString() operation on this value.
828   bool ToStringCanBeObserved() const {
829     return ToStringOrToNumberCanBeObserved();
830   }
831
832   // Returns true conservatively if the program might be able to observe a
833   // ToNumber() operation on this value.
834   bool ToNumberCanBeObserved() const {
835     return ToStringOrToNumberCanBeObserved();
836   }
837
838   MinusZeroMode GetMinusZeroMode() {
839     return CheckFlag(kBailoutOnMinusZero)
840         ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
841   }
842
843  protected:
844   // This function must be overridden for instructions with flag kUseGVN, to
845   // compare the non-Operand parts of the instruction.
846   virtual bool DataEquals(HValue* other) {
847     UNREACHABLE();
848     return false;
849   }
850
851   bool ToStringOrToNumberCanBeObserved() const {
852     if (type().IsTaggedPrimitive()) return false;
853     if (type().IsJSObject()) return true;
854     return !representation().IsSmiOrInteger32() && !representation().IsDouble();
855   }
856
857   virtual Representation RepresentationFromInputs() {
858     return representation();
859   }
860   virtual Representation RepresentationFromUses();
861   Representation RepresentationFromUseRequirements();
862   bool HasNonSmiUse();
863   virtual void UpdateRepresentation(Representation new_rep,
864                                     HInferRepresentationPhase* h_infer,
865                                     const char* reason);
866   void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
867
868   virtual void RepresentationChanged(Representation to) { }
869
870   virtual Range* InferRange(Zone* zone);
871   virtual void DeleteFromGraph() = 0;
872   virtual void InternalSetOperandAt(int index, HValue* value) = 0;
873   void clear_block() {
874     DCHECK(block_ != NULL);
875     block_ = NULL;
876   }
877
878   void set_representation(Representation r) {
879     DCHECK(representation_.IsNone() && !r.IsNone());
880     representation_ = r;
881   }
882
883   static GVNFlagSet AllFlagSet() {
884     GVNFlagSet result;
885 #define ADD_FLAG(Type) result.Add(k##Type);
886   GVN_TRACKED_FLAG_LIST(ADD_FLAG)
887   GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
888 #undef ADD_FLAG
889     return result;
890   }
891
892   // A flag mask to mark an instruction as having arbitrary side effects.
893   static GVNFlagSet AllSideEffectsFlagSet() {
894     GVNFlagSet result = AllFlagSet();
895     result.Remove(kOsrEntries);
896     return result;
897   }
898   friend OStream& operator<<(OStream& os, const ChangesOf& v);
899
900   // A flag mask of all side effects that can make observable changes in
901   // an executing program (i.e. are not safe to repeat, move or remove);
902   static GVNFlagSet AllObservableSideEffectsFlagSet() {
903     GVNFlagSet result = AllFlagSet();
904     result.Remove(kNewSpacePromotion);
905     result.Remove(kElementsKind);
906     result.Remove(kElementsPointer);
907     result.Remove(kMaps);
908     return result;
909   }
910
911   // Remove the matching use from the use list if present.  Returns the
912   // removed list node or NULL.
913   HUseListNode* RemoveUse(HValue* value, int index);
914
915   void RegisterUse(int index, HValue* new_value);
916
917   HBasicBlock* block_;
918
919   // The id of this instruction in the hydrogen graph, assigned when first
920   // added to the graph. Reflects creation order.
921   int id_;
922
923   Representation representation_;
924   HType type_;
925   HUseListNode* use_list_;
926   Range* range_;
927 #ifdef DEBUG
928   bool range_poisoned_;
929 #endif
930   int flags_;
931   GVNFlagSet changes_flags_;
932   GVNFlagSet depends_on_flags_;
933
934  private:
935   virtual bool IsDeletable() const { return false; }
936
937   DISALLOW_COPY_AND_ASSIGN(HValue);
938 };
939
940 // Support for printing various aspects of an HValue.
941 struct NameOf {
942   explicit NameOf(const HValue* const v) : value(v) {}
943   const HValue* value;
944 };
945
946
947 struct TypeOf {
948   explicit TypeOf(const HValue* const v) : value(v) {}
949   const HValue* value;
950 };
951
952
953 struct ChangesOf {
954   explicit ChangesOf(const HValue* const v) : value(v) {}
955   const HValue* value;
956 };
957
958
959 OStream& operator<<(OStream& os, const HValue& v);
960 OStream& operator<<(OStream& os, const NameOf& v);
961 OStream& operator<<(OStream& os, const TypeOf& v);
962 OStream& operator<<(OStream& os, const ChangesOf& v);
963
964
965 #define DECLARE_INSTRUCTION_FACTORY_P0(I)                                      \
966   static I* New(Zone* zone, HValue* context) {                                 \
967     return new(zone) I();                                                      \
968 }
969
970 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1)                                  \
971   static I* New(Zone* zone, HValue* context, P1 p1) {                          \
972     return new(zone) I(p1);                                                    \
973   }
974
975 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2)                              \
976   static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) {                   \
977     return new(zone) I(p1, p2);                                                \
978   }
979
980 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3)                          \
981   static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) {            \
982     return new(zone) I(p1, p2, p3);                                            \
983   }
984
985 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4)                      \
986   static I* New(Zone* zone,                                                    \
987                 HValue* context,                                               \
988                 P1 p1,                                                         \
989                 P2 p2,                                                         \
990                 P3 p3,                                                         \
991                 P4 p4) {                                                       \
992     return new(zone) I(p1, p2, p3, p4);                                        \
993   }
994
995 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5)                  \
996   static I* New(Zone* zone,                                                    \
997                 HValue* context,                                               \
998                 P1 p1,                                                         \
999                 P2 p2,                                                         \
1000                 P3 p3,                                                         \
1001                 P4 p4,                                                         \
1002                 P5 p5) {                                                       \
1003     return new(zone) I(p1, p2, p3, p4, p5);                                    \
1004   }
1005
1006 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6)              \
1007   static I* New(Zone* zone,                                                    \
1008                 HValue* context,                                               \
1009                 P1 p1,                                                         \
1010                 P2 p2,                                                         \
1011                 P3 p3,                                                         \
1012                 P4 p4,                                                         \
1013                 P5 p5,                                                         \
1014                 P6 p6) {                                                       \
1015     return new(zone) I(p1, p2, p3, p4, p5, p6);                                \
1016   }
1017
1018 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I)                         \
1019   static I* New(Zone* zone, HValue* context) {                                 \
1020     return new(zone) I(context);                                               \
1021   }
1022
1023 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1)                     \
1024   static I* New(Zone* zone, HValue* context, P1 p1) {                          \
1025     return new(zone) I(context, p1);                                           \
1026   }
1027
1028 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2)                 \
1029   static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) {                   \
1030     return new(zone) I(context, p1, p2);                                       \
1031   }
1032
1033 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3)             \
1034   static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) {            \
1035     return new(zone) I(context, p1, p2, p3);                                   \
1036   }
1037
1038 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4)         \
1039   static I* New(Zone* zone,                                                    \
1040                 HValue* context,                                               \
1041                 P1 p1,                                                         \
1042                 P2 p2,                                                         \
1043                 P3 p3,                                                         \
1044                 P4 p4) {                                                       \
1045     return new(zone) I(context, p1, p2, p3, p4);                               \
1046   }
1047
1048 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5)     \
1049   static I* New(Zone* zone,                                                    \
1050                 HValue* context,                                               \
1051                 P1 p1,                                                         \
1052                 P2 p2,                                                         \
1053                 P3 p3,                                                         \
1054                 P4 p4,                                                         \
1055                 P5 p5) {                                                       \
1056     return new(zone) I(context, p1, p2, p3, p4, p5);                           \
1057   }
1058
1059
1060 // A helper class to represent per-operand position information attached to
1061 // the HInstruction in the compact form. Uses tagging to distinguish between
1062 // case when only instruction's position is available and case when operands'
1063 // positions are also available.
1064 // In the first case it contains intruction's position as a tagged value.
1065 // In the second case it points to an array which contains instruction's
1066 // position and operands' positions.
1067 class HPositionInfo {
1068  public:
1069   explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
1070
1071   HSourcePosition position() const {
1072     if (has_operand_positions()) {
1073       return operand_positions()[kInstructionPosIndex];
1074     }
1075     return HSourcePosition(static_cast<int>(UntagPosition(data_)));
1076   }
1077
1078   void set_position(HSourcePosition pos) {
1079     if (has_operand_positions()) {
1080       operand_positions()[kInstructionPosIndex] = pos;
1081     } else {
1082       data_ = TagPosition(pos.raw());
1083     }
1084   }
1085
1086   void ensure_storage_for_operand_positions(Zone* zone, int operand_count) {
1087     if (has_operand_positions()) {
1088       return;
1089     }
1090
1091     const int length = kFirstOperandPosIndex + operand_count;
1092     HSourcePosition* positions =
1093         zone->NewArray<HSourcePosition>(length);
1094     for (int i = 0; i < length; i++) {
1095       positions[i] = HSourcePosition::Unknown();
1096     }
1097
1098     const HSourcePosition pos = position();
1099     data_ = reinterpret_cast<intptr_t>(positions);
1100     set_position(pos);
1101
1102     DCHECK(has_operand_positions());
1103   }
1104
1105   HSourcePosition operand_position(int idx) const {
1106     if (!has_operand_positions()) {
1107       return position();
1108     }
1109     return *operand_position_slot(idx);
1110   }
1111
1112   void set_operand_position(int idx, HSourcePosition pos) {
1113     *operand_position_slot(idx) = pos;
1114   }
1115
1116  private:
1117   static const intptr_t kInstructionPosIndex = 0;
1118   static const intptr_t kFirstOperandPosIndex = 1;
1119
1120   HSourcePosition* operand_position_slot(int idx) const {
1121     DCHECK(has_operand_positions());
1122     return &(operand_positions()[kFirstOperandPosIndex + idx]);
1123   }
1124
1125   bool has_operand_positions() const {
1126     return !IsTaggedPosition(data_);
1127   }
1128
1129   HSourcePosition* operand_positions() const {
1130     DCHECK(has_operand_positions());
1131     return reinterpret_cast<HSourcePosition*>(data_);
1132   }
1133
1134   static const intptr_t kPositionTag = 1;
1135   static const intptr_t kPositionShift = 1;
1136   static bool IsTaggedPosition(intptr_t val) {
1137     return (val & kPositionTag) != 0;
1138   }
1139   static intptr_t UntagPosition(intptr_t val) {
1140     DCHECK(IsTaggedPosition(val));
1141     return val >> kPositionShift;
1142   }
1143   static intptr_t TagPosition(intptr_t val) {
1144     const intptr_t result = (val << kPositionShift) | kPositionTag;
1145     DCHECK(UntagPosition(result) == val);
1146     return result;
1147   }
1148
1149   intptr_t data_;
1150 };
1151
1152
1153 class HInstruction : public HValue {
1154  public:
1155   HInstruction* next() const { return next_; }
1156   HInstruction* previous() const { return previous_; }
1157
1158   virtual OStream& PrintTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1159   virtual OStream& PrintDataTo(OStream& os) const;          // NOLINT
1160
1161   bool IsLinked() const { return block() != NULL; }
1162   void Unlink();
1163
1164   void InsertBefore(HInstruction* next);
1165
1166   template<class T> T* Prepend(T* instr) {
1167     instr->InsertBefore(this);
1168     return instr;
1169   }
1170
1171   void InsertAfter(HInstruction* previous);
1172
1173   template<class T> T* Append(T* instr) {
1174     instr->InsertAfter(this);
1175     return instr;
1176   }
1177
1178   // The position is a write-once variable.
1179   virtual HSourcePosition position() const V8_OVERRIDE {
1180     return HSourcePosition(position_.position());
1181   }
1182   bool has_position() const {
1183     return !position().IsUnknown();
1184   }
1185   void set_position(HSourcePosition position) {
1186     DCHECK(!has_position());
1187     DCHECK(!position.IsUnknown());
1188     position_.set_position(position);
1189   }
1190
1191   virtual HSourcePosition operand_position(int index) const V8_OVERRIDE {
1192     const HSourcePosition pos = position_.operand_position(index);
1193     return pos.IsUnknown() ? position() : pos;
1194   }
1195   void set_operand_position(Zone* zone, int index, HSourcePosition pos) {
1196     DCHECK(0 <= index && index < OperandCount());
1197     position_.ensure_storage_for_operand_positions(zone, OperandCount());
1198     position_.set_operand_position(index, pos);
1199   }
1200
1201   bool Dominates(HInstruction* other);
1202   bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
1203   bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
1204
1205   virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
1206
1207 #ifdef DEBUG
1208   virtual void Verify() V8_OVERRIDE;
1209 #endif
1210
1211   bool CanDeoptimize();
1212
1213   virtual bool HasStackCheck() { return false; }
1214
1215   DECLARE_ABSTRACT_INSTRUCTION(Instruction)
1216
1217  protected:
1218   explicit HInstruction(HType type = HType::Tagged())
1219       : HValue(type),
1220         next_(NULL),
1221         previous_(NULL),
1222         position_(RelocInfo::kNoPosition) {
1223     SetDependsOnFlag(kOsrEntries);
1224   }
1225
1226   virtual void DeleteFromGraph() V8_OVERRIDE { Unlink(); }
1227
1228  private:
1229   void InitializeAsFirst(HBasicBlock* block) {
1230     DCHECK(!IsLinked());
1231     SetBlock(block);
1232   }
1233
1234   HInstruction* next_;
1235   HInstruction* previous_;
1236   HPositionInfo position_;
1237
1238   friend class HBasicBlock;
1239 };
1240
1241
1242 template<int V>
1243 class HTemplateInstruction : public HInstruction {
1244  public:
1245   virtual int OperandCount() const V8_FINAL V8_OVERRIDE { return V; }
1246   virtual HValue* OperandAt(int i) const V8_FINAL V8_OVERRIDE {
1247     return inputs_[i];
1248   }
1249
1250  protected:
1251   explicit HTemplateInstruction(HType type = HType::Tagged())
1252       : HInstruction(type) {}
1253
1254   virtual void InternalSetOperandAt(int i, HValue* value) V8_FINAL V8_OVERRIDE {
1255     inputs_[i] = value;
1256   }
1257
1258  private:
1259   EmbeddedContainer<HValue*, V> inputs_;
1260 };
1261
1262
1263 class HControlInstruction : public HInstruction {
1264  public:
1265   virtual HBasicBlock* SuccessorAt(int i) const = 0;
1266   virtual int SuccessorCount() const = 0;
1267   virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
1268
1269   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1270
1271   virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1272     *block = NULL;
1273     return false;
1274   }
1275
1276   HBasicBlock* FirstSuccessor() {
1277     return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1278   }
1279   HBasicBlock* SecondSuccessor() {
1280     return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1281   }
1282
1283   void Not() {
1284     HBasicBlock* swap = SuccessorAt(0);
1285     SetSuccessorAt(0, SuccessorAt(1));
1286     SetSuccessorAt(1, swap);
1287   }
1288
1289   DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
1290 };
1291
1292
1293 class HSuccessorIterator V8_FINAL BASE_EMBEDDED {
1294  public:
1295   explicit HSuccessorIterator(const HControlInstruction* instr)
1296       : instr_(instr), current_(0) {}
1297
1298   bool Done() { return current_ >= instr_->SuccessorCount(); }
1299   HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
1300   void Advance() { current_++; }
1301
1302  private:
1303   const HControlInstruction* instr_;
1304   int current_;
1305 };
1306
1307
1308 template<int S, int V>
1309 class HTemplateControlInstruction : public HControlInstruction {
1310  public:
1311   int SuccessorCount() const V8_OVERRIDE { return S; }
1312   HBasicBlock* SuccessorAt(int i) const V8_OVERRIDE { return successors_[i]; }
1313   void SetSuccessorAt(int i, HBasicBlock* block) V8_OVERRIDE {
1314     successors_[i] = block;
1315   }
1316
1317   int OperandCount() const V8_OVERRIDE { return V; }
1318   HValue* OperandAt(int i) const V8_OVERRIDE { return inputs_[i]; }
1319
1320
1321  protected:
1322   void InternalSetOperandAt(int i, HValue* value) V8_OVERRIDE {
1323     inputs_[i] = value;
1324   }
1325
1326  private:
1327   EmbeddedContainer<HBasicBlock*, S> successors_;
1328   EmbeddedContainer<HValue*, V> inputs_;
1329 };
1330
1331
1332 class HBlockEntry V8_FINAL : public HTemplateInstruction<0> {
1333  public:
1334   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1335     return Representation::None();
1336   }
1337
1338   DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
1339 };
1340
1341
1342 class HDummyUse V8_FINAL : public HTemplateInstruction<1> {
1343  public:
1344   explicit HDummyUse(HValue* value)
1345       : HTemplateInstruction<1>(HType::Smi()) {
1346     SetOperandAt(0, value);
1347     // Pretend to be a Smi so that the HChange instructions inserted
1348     // before any use generate as little code as possible.
1349     set_representation(Representation::Tagged());
1350   }
1351
1352   HValue* value() const { return OperandAt(0); }
1353
1354   virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
1355   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1356     return Representation::None();
1357   }
1358
1359   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1360
1361   DECLARE_CONCRETE_INSTRUCTION(DummyUse);
1362 };
1363
1364
1365 // Inserts an int3/stop break instruction for debugging purposes.
1366 class HDebugBreak V8_FINAL : public HTemplateInstruction<0> {
1367  public:
1368   DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak);
1369
1370   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1371     return Representation::None();
1372   }
1373
1374   DECLARE_CONCRETE_INSTRUCTION(DebugBreak)
1375 };
1376
1377
1378 class HGoto V8_FINAL : public HTemplateControlInstruction<1, 0> {
1379  public:
1380   explicit HGoto(HBasicBlock* target) {
1381     SetSuccessorAt(0, target);
1382   }
1383
1384   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE {
1385     *block = FirstSuccessor();
1386     return true;
1387   }
1388
1389   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1390     return Representation::None();
1391   }
1392
1393   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1394
1395   DECLARE_CONCRETE_INSTRUCTION(Goto)
1396 };
1397
1398
1399 class HDeoptimize V8_FINAL : public HTemplateControlInstruction<1, 0> {
1400  public:
1401   static HDeoptimize* New(Zone* zone,
1402                           HValue* context,
1403                           const char* reason,
1404                           Deoptimizer::BailoutType type,
1405                           HBasicBlock* unreachable_continuation) {
1406     return new(zone) HDeoptimize(reason, type, unreachable_continuation);
1407   }
1408
1409   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE {
1410     *block = NULL;
1411     return true;
1412   }
1413
1414   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1415     return Representation::None();
1416   }
1417
1418   const char* reason() const { return reason_; }
1419   Deoptimizer::BailoutType type() { return type_; }
1420
1421   DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
1422
1423  private:
1424   explicit HDeoptimize(const char* reason,
1425                        Deoptimizer::BailoutType type,
1426                        HBasicBlock* unreachable_continuation)
1427       : reason_(reason), type_(type) {
1428     SetSuccessorAt(0, unreachable_continuation);
1429   }
1430
1431   const char* reason_;
1432   Deoptimizer::BailoutType type_;
1433 };
1434
1435
1436 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> {
1437  public:
1438   HUnaryControlInstruction(HValue* value,
1439                            HBasicBlock* true_target,
1440                            HBasicBlock* false_target) {
1441     SetOperandAt(0, value);
1442     SetSuccessorAt(0, true_target);
1443     SetSuccessorAt(1, false_target);
1444   }
1445
1446   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1447
1448   HValue* value() const { return OperandAt(0); }
1449 };
1450
1451
1452 class HBranch V8_FINAL : public HUnaryControlInstruction {
1453  public:
1454   DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*);
1455   DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*,
1456                                  ToBooleanStub::Types);
1457   DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*,
1458                                  ToBooleanStub::Types,
1459                                  HBasicBlock*, HBasicBlock*);
1460
1461   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1462     return Representation::None();
1463   }
1464   virtual Representation observed_input_representation(int index) V8_OVERRIDE;
1465
1466   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
1467
1468   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1469
1470   ToBooleanStub::Types expected_input_types() const {
1471     return expected_input_types_;
1472   }
1473
1474   DECLARE_CONCRETE_INSTRUCTION(Branch)
1475
1476  private:
1477   HBranch(HValue* value,
1478           ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
1479           HBasicBlock* true_target = NULL,
1480           HBasicBlock* false_target = NULL)
1481       : HUnaryControlInstruction(value, true_target, false_target),
1482         expected_input_types_(expected_input_types) {
1483     SetFlag(kAllowUndefinedAsNaN);
1484   }
1485
1486   ToBooleanStub::Types expected_input_types_;
1487 };
1488
1489
1490 class HCompareMap V8_FINAL : public HUnaryControlInstruction {
1491  public:
1492   DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>);
1493   DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>,
1494                                  HBasicBlock*, HBasicBlock*);
1495
1496   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE {
1497     if (known_successor_index() != kNoKnownSuccessorIndex) {
1498       *block = SuccessorAt(known_successor_index());
1499       return true;
1500     }
1501     *block = NULL;
1502     return false;
1503   }
1504
1505   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1506
1507   static const int kNoKnownSuccessorIndex = -1;
1508   int known_successor_index() const { return known_successor_index_; }
1509   void set_known_successor_index(int known_successor_index) {
1510     known_successor_index_ = known_successor_index;
1511   }
1512
1513   Unique<Map> map() const { return map_; }
1514   bool map_is_stable() const { return map_is_stable_; }
1515
1516   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1517     return Representation::Tagged();
1518   }
1519
1520   DECLARE_CONCRETE_INSTRUCTION(CompareMap)
1521
1522  protected:
1523   virtual int RedefinedOperandIndex() { return 0; }
1524
1525  private:
1526   HCompareMap(HValue* value,
1527               Handle<Map> map,
1528               HBasicBlock* true_target = NULL,
1529               HBasicBlock* false_target = NULL)
1530       : HUnaryControlInstruction(value, true_target, false_target),
1531         known_successor_index_(kNoKnownSuccessorIndex),
1532         map_is_stable_(map->is_stable()),
1533         map_(Unique<Map>::CreateImmovable(map)) {
1534     set_representation(Representation::Tagged());
1535   }
1536
1537   int known_successor_index_ : 31;
1538   bool map_is_stable_ : 1;
1539   Unique<Map> map_;
1540 };
1541
1542
1543 class HContext V8_FINAL : public HTemplateInstruction<0> {
1544  public:
1545   static HContext* New(Zone* zone) {
1546     return new(zone) HContext();
1547   }
1548
1549   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1550     return Representation::None();
1551   }
1552
1553   DECLARE_CONCRETE_INSTRUCTION(Context)
1554
1555  protected:
1556   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1557
1558  private:
1559   HContext() {
1560     set_representation(Representation::Tagged());
1561     SetFlag(kUseGVN);
1562   }
1563
1564   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1565 };
1566
1567
1568 class HReturn V8_FINAL : public HTemplateControlInstruction<0, 3> {
1569  public:
1570   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*);
1571   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*);
1572
1573   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1574     // TODO(titzer): require an Int32 input for faster returns.
1575     if (index == 2) return Representation::Smi();
1576     return Representation::Tagged();
1577   }
1578
1579   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1580
1581   HValue* value() const { return OperandAt(0); }
1582   HValue* context() const { return OperandAt(1); }
1583   HValue* parameter_count() const { return OperandAt(2); }
1584
1585   DECLARE_CONCRETE_INSTRUCTION(Return)
1586
1587  private:
1588   HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) {
1589     SetOperandAt(0, value);
1590     SetOperandAt(1, context);
1591     SetOperandAt(2, parameter_count);
1592   }
1593 };
1594
1595
1596 class HAbnormalExit V8_FINAL : public HTemplateControlInstruction<0, 0> {
1597  public:
1598   DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit);
1599
1600   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1601     return Representation::None();
1602   }
1603
1604   DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
1605  private:
1606   HAbnormalExit() {}
1607 };
1608
1609
1610 class HUnaryOperation : public HTemplateInstruction<1> {
1611  public:
1612   explicit HUnaryOperation(HValue* value, HType type = HType::Tagged())
1613       : HTemplateInstruction<1>(type) {
1614     SetOperandAt(0, value);
1615   }
1616
1617   static HUnaryOperation* cast(HValue* value) {
1618     return reinterpret_cast<HUnaryOperation*>(value);
1619   }
1620
1621   HValue* value() const { return OperandAt(0); }
1622   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1623 };
1624
1625
1626 class HUseConst V8_FINAL : public HUnaryOperation {
1627  public:
1628   DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*);
1629
1630   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1631     return Representation::None();
1632   }
1633
1634   DECLARE_CONCRETE_INSTRUCTION(UseConst)
1635
1636  private:
1637     explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
1638 };
1639
1640
1641 class HForceRepresentation V8_FINAL : public HTemplateInstruction<1> {
1642  public:
1643   static HInstruction* New(Zone* zone, HValue* context, HValue* value,
1644                            Representation required_representation);
1645
1646   HValue* value() const { return OperandAt(0); }
1647
1648   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1649     return representation();  // Same as the output representation.
1650   }
1651
1652   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1653
1654   DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
1655
1656  private:
1657   HForceRepresentation(HValue* value, Representation required_representation) {
1658     SetOperandAt(0, value);
1659     set_representation(required_representation);
1660   }
1661 };
1662
1663
1664 class HChange V8_FINAL : public HUnaryOperation {
1665  public:
1666   HChange(HValue* value,
1667           Representation to,
1668           bool is_truncating_to_smi,
1669           bool is_truncating_to_int32)
1670       : HUnaryOperation(value) {
1671     DCHECK(!value->representation().IsNone());
1672     DCHECK(!to.IsNone());
1673     DCHECK(!value->representation().Equals(to));
1674     set_representation(to);
1675     SetFlag(kUseGVN);
1676     SetFlag(kCanOverflow);
1677     if (is_truncating_to_smi && to.IsSmi()) {
1678       SetFlag(kTruncatingToSmi);
1679       SetFlag(kTruncatingToInt32);
1680     }
1681     if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
1682     if (value->representation().IsSmi() || value->type().IsSmi()) {
1683       set_type(HType::Smi());
1684     } else {
1685       if (to.IsFloat32x4()) {
1686         set_type(HType::Float32x4());
1687       } else if (to.IsFloat64x2()) {
1688         set_type(HType::Float64x2());
1689       } else if (to.IsInt32x4()) {
1690         set_type(HType::Int32x4());
1691       } else {
1692         set_type(HType::TaggedNumber());
1693       }
1694       if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
1695     }
1696   }
1697
1698   bool can_convert_undefined_to_nan() {
1699     return CheckUsesForFlag(kAllowUndefinedAsNaN);
1700   }
1701
1702   virtual HType CalculateInferredType() V8_OVERRIDE;
1703   virtual HValue* Canonicalize() V8_OVERRIDE;
1704
1705   Representation from() const { return value()->representation(); }
1706   Representation to() const { return representation(); }
1707   bool deoptimize_on_minus_zero() const {
1708     return CheckFlag(kBailoutOnMinusZero);
1709   }
1710   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1711     return from();
1712   }
1713
1714   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
1715
1716   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1717
1718   DECLARE_CONCRETE_INSTRUCTION(Change)
1719
1720  protected:
1721   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1722
1723  private:
1724   virtual bool IsDeletable() const V8_OVERRIDE {
1725     return !from().IsTagged() || value()->type().IsSmi();
1726   }
1727 };
1728
1729
1730 class HClampToUint8 V8_FINAL : public HUnaryOperation {
1731  public:
1732   DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*);
1733
1734   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1735     return Representation::None();
1736   }
1737
1738   DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1739
1740  protected:
1741   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1742
1743  private:
1744   explicit HClampToUint8(HValue* value)
1745       : HUnaryOperation(value) {
1746     set_representation(Representation::Integer32());
1747     SetFlag(kAllowUndefinedAsNaN);
1748     SetFlag(kUseGVN);
1749   }
1750
1751   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1752 };
1753
1754
1755 class HDoubleBits V8_FINAL : public HUnaryOperation {
1756  public:
1757   enum Bits { HIGH, LOW };
1758   DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits);
1759
1760   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1761     return Representation::Double();
1762   }
1763
1764   DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1765
1766   Bits bits() { return bits_; }
1767
1768  protected:
1769   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
1770     return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1771   }
1772
1773  private:
1774   HDoubleBits(HValue* value, Bits bits)
1775       : HUnaryOperation(value), bits_(bits) {
1776     set_representation(Representation::Integer32());
1777     SetFlag(kUseGVN);
1778   }
1779
1780   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1781
1782   Bits bits_;
1783 };
1784
1785
1786 class HConstructDouble V8_FINAL : public HTemplateInstruction<2> {
1787  public:
1788   DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*);
1789
1790   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1791     return Representation::Integer32();
1792   }
1793
1794   DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1795
1796   HValue* hi() { return OperandAt(0); }
1797   HValue* lo() { return OperandAt(1); }
1798
1799  protected:
1800   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
1801
1802  private:
1803   explicit HConstructDouble(HValue* hi, HValue* lo) {
1804     set_representation(Representation::Double());
1805     SetFlag(kUseGVN);
1806     SetOperandAt(0, hi);
1807     SetOperandAt(1, lo);
1808   }
1809
1810   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
1811 };
1812
1813
1814 enum RemovableSimulate {
1815   REMOVABLE_SIMULATE,
1816   FIXED_SIMULATE
1817 };
1818
1819
1820 class HSimulate V8_FINAL : public HInstruction {
1821  public:
1822   HSimulate(BailoutId ast_id,
1823             int pop_count,
1824             Zone* zone,
1825             RemovableSimulate removable)
1826       : ast_id_(ast_id),
1827         pop_count_(pop_count),
1828         values_(2, zone),
1829         assigned_indexes_(2, zone),
1830         zone_(zone),
1831         removable_(removable),
1832         done_with_replay_(false) {}
1833   ~HSimulate() {}
1834
1835   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1836
1837   bool HasAstId() const { return !ast_id_.IsNone(); }
1838   BailoutId ast_id() const { return ast_id_; }
1839   void set_ast_id(BailoutId id) {
1840     DCHECK(!HasAstId());
1841     ast_id_ = id;
1842   }
1843
1844   int pop_count() const { return pop_count_; }
1845   const ZoneList<HValue*>* values() const { return &values_; }
1846   int GetAssignedIndexAt(int index) const {
1847     DCHECK(HasAssignedIndexAt(index));
1848     return assigned_indexes_[index];
1849   }
1850   bool HasAssignedIndexAt(int index) const {
1851     return assigned_indexes_[index] != kNoIndex;
1852   }
1853   void AddAssignedValue(int index, HValue* value) {
1854     AddValue(index, value);
1855   }
1856   void AddPushedValue(HValue* value) {
1857     AddValue(kNoIndex, value);
1858   }
1859   int ToOperandIndex(int environment_index) {
1860     for (int i = 0; i < assigned_indexes_.length(); ++i) {
1861       if (assigned_indexes_[i] == environment_index) return i;
1862     }
1863     return -1;
1864   }
1865   virtual int OperandCount() const V8_OVERRIDE { return values_.length(); }
1866   virtual HValue* OperandAt(int index) const V8_OVERRIDE {
1867     return values_[index];
1868   }
1869
1870   virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
1871   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1872     return Representation::None();
1873   }
1874
1875   void MergeWith(ZoneList<HSimulate*>* list);
1876   bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
1877
1878   // Replay effects of this instruction on the given environment.
1879   void ReplayEnvironment(HEnvironment* env);
1880
1881   DECLARE_CONCRETE_INSTRUCTION(Simulate)
1882
1883 #ifdef DEBUG
1884   virtual void Verify() V8_OVERRIDE;
1885   void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
1886   Handle<JSFunction> closure() const { return closure_; }
1887 #endif
1888
1889  protected:
1890   virtual void InternalSetOperandAt(int index, HValue* value) V8_OVERRIDE {
1891     values_[index] = value;
1892   }
1893
1894  private:
1895   static const int kNoIndex = -1;
1896   void AddValue(int index, HValue* value) {
1897     assigned_indexes_.Add(index, zone_);
1898     // Resize the list of pushed values.
1899     values_.Add(NULL, zone_);
1900     // Set the operand through the base method in HValue to make sure that the
1901     // use lists are correctly updated.
1902     SetOperandAt(values_.length() - 1, value);
1903   }
1904   bool HasValueForIndex(int index) {
1905     for (int i = 0; i < assigned_indexes_.length(); ++i) {
1906       if (assigned_indexes_[i] == index) return true;
1907     }
1908     return false;
1909   }
1910   BailoutId ast_id_;
1911   int pop_count_;
1912   ZoneList<HValue*> values_;
1913   ZoneList<int> assigned_indexes_;
1914   Zone* zone_;
1915   RemovableSimulate removable_ : 2;
1916   bool done_with_replay_ : 1;
1917
1918 #ifdef DEBUG
1919   Handle<JSFunction> closure_;
1920 #endif
1921 };
1922
1923
1924 class HEnvironmentMarker V8_FINAL : public HTemplateInstruction<1> {
1925  public:
1926   enum Kind { BIND, LOOKUP };
1927
1928   DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
1929
1930   Kind kind() const { return kind_; }
1931   int index() const { return index_; }
1932   HSimulate* next_simulate() { return next_simulate_; }
1933   void set_next_simulate(HSimulate* simulate) {
1934     next_simulate_ = simulate;
1935   }
1936
1937   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1938     return Representation::None();
1939   }
1940
1941   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
1942
1943 #ifdef DEBUG
1944   void set_closure(Handle<JSFunction> closure) {
1945     DCHECK(closure_.is_null());
1946     DCHECK(!closure.is_null());
1947     closure_ = closure;
1948   }
1949   Handle<JSFunction> closure() const { return closure_; }
1950 #endif
1951
1952   DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1953
1954  private:
1955   HEnvironmentMarker(Kind kind, int index)
1956       : kind_(kind), index_(index), next_simulate_(NULL) { }
1957
1958   Kind kind_;
1959   int index_;
1960   HSimulate* next_simulate_;
1961
1962 #ifdef DEBUG
1963   Handle<JSFunction> closure_;
1964 #endif
1965 };
1966
1967
1968 class HStackCheck V8_FINAL : public HTemplateInstruction<1> {
1969  public:
1970   enum Type {
1971     kFunctionEntry,
1972     kBackwardsBranch
1973   };
1974
1975   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type);
1976
1977   HValue* context() { return OperandAt(0); }
1978
1979   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
1980     return Representation::Tagged();
1981   }
1982
1983   void Eliminate() {
1984     // The stack check eliminator might try to eliminate the same stack
1985     // check instruction multiple times.
1986     if (IsLinked()) {
1987       DeleteAndReplaceWith(NULL);
1988     }
1989   }
1990
1991   bool is_function_entry() { return type_ == kFunctionEntry; }
1992   bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1993
1994   DECLARE_CONCRETE_INSTRUCTION(StackCheck)
1995
1996  private:
1997   HStackCheck(HValue* context, Type type) : type_(type) {
1998     SetOperandAt(0, context);
1999     SetChangesFlag(kNewSpacePromotion);
2000   }
2001
2002   Type type_;
2003 };
2004
2005
2006 enum InliningKind {
2007   NORMAL_RETURN,          // Drop the function from the environment on return.
2008   CONSTRUCT_CALL_RETURN,  // Either use allocated receiver or return value.
2009   GETTER_CALL_RETURN,     // Returning from a getter, need to restore context.
2010   SETTER_CALL_RETURN      // Use the RHS of the assignment as the return value.
2011 };
2012
2013
2014 class HArgumentsObject;
2015
2016
2017 class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
2018  public:
2019   static HEnterInlined* New(Zone* zone,
2020                             HValue* context,
2021                             BailoutId return_id,
2022                             Handle<JSFunction> closure,
2023                             int arguments_count,
2024                             FunctionLiteral* function,
2025                             InliningKind inlining_kind,
2026                             Variable* arguments_var,
2027                             HArgumentsObject* arguments_object) {
2028     return new(zone) HEnterInlined(return_id, closure, arguments_count,
2029                                    function, inlining_kind, arguments_var,
2030                                    arguments_object, zone);
2031   }
2032
2033   void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone);
2034   ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
2035
2036   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2037
2038   Handle<JSFunction> closure() const { return closure_; }
2039   int arguments_count() const { return arguments_count_; }
2040   bool arguments_pushed() const { return arguments_pushed_; }
2041   void set_arguments_pushed() { arguments_pushed_ = true; }
2042   FunctionLiteral* function() const { return function_; }
2043   InliningKind inlining_kind() const { return inlining_kind_; }
2044   BailoutId ReturnId() const { return return_id_; }
2045
2046   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2047     return Representation::None();
2048   }
2049
2050   Variable* arguments_var() { return arguments_var_; }
2051   HArgumentsObject* arguments_object() { return arguments_object_; }
2052
2053   DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
2054
2055  private:
2056   HEnterInlined(BailoutId return_id,
2057                 Handle<JSFunction> closure,
2058                 int arguments_count,
2059                 FunctionLiteral* function,
2060                 InliningKind inlining_kind,
2061                 Variable* arguments_var,
2062                 HArgumentsObject* arguments_object,
2063                 Zone* zone)
2064       : return_id_(return_id),
2065         closure_(closure),
2066         arguments_count_(arguments_count),
2067         arguments_pushed_(false),
2068         function_(function),
2069         inlining_kind_(inlining_kind),
2070         arguments_var_(arguments_var),
2071         arguments_object_(arguments_object),
2072         return_targets_(2, zone) {
2073   }
2074
2075   BailoutId return_id_;
2076   Handle<JSFunction> closure_;
2077   int arguments_count_;
2078   bool arguments_pushed_;
2079   FunctionLiteral* function_;
2080   InliningKind inlining_kind_;
2081   Variable* arguments_var_;
2082   HArgumentsObject* arguments_object_;
2083   ZoneList<HBasicBlock*> return_targets_;
2084 };
2085
2086
2087 class HLeaveInlined V8_FINAL : public HTemplateInstruction<0> {
2088  public:
2089   HLeaveInlined(HEnterInlined* entry,
2090                 int drop_count)
2091       : entry_(entry),
2092         drop_count_(drop_count) { }
2093
2094   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2095     return Representation::None();
2096   }
2097
2098   virtual int argument_delta() const V8_OVERRIDE {
2099     return entry_->arguments_pushed() ? -drop_count_ : 0;
2100   }
2101
2102   DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
2103
2104  private:
2105   HEnterInlined* entry_;
2106   int drop_count_;
2107 };
2108
2109
2110 class HPushArguments V8_FINAL : public HInstruction {
2111  public:
2112   static HPushArguments* New(Zone* zone, HValue* context) {
2113     return new(zone) HPushArguments(zone);
2114   }
2115   static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1) {
2116     HPushArguments* instr = new(zone) HPushArguments(zone);
2117     instr->AddInput(arg1);
2118     return instr;
2119   }
2120   static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2121                              HValue* arg2) {
2122     HPushArguments* instr = new(zone) HPushArguments(zone);
2123     instr->AddInput(arg1);
2124     instr->AddInput(arg2);
2125     return instr;
2126   }
2127   static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2128                              HValue* arg2, HValue* arg3) {
2129     HPushArguments* instr = new(zone) HPushArguments(zone);
2130     instr->AddInput(arg1);
2131     instr->AddInput(arg2);
2132     instr->AddInput(arg3);
2133     return instr;
2134   }
2135   static HPushArguments* New(Zone* zone, HValue* context, HValue* arg1,
2136                              HValue* arg2, HValue* arg3, HValue* arg4) {
2137     HPushArguments* instr = new(zone) HPushArguments(zone);
2138     instr->AddInput(arg1);
2139     instr->AddInput(arg2);
2140     instr->AddInput(arg3);
2141     instr->AddInput(arg4);
2142     return instr;
2143   }
2144
2145   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2146     return Representation::Tagged();
2147   }
2148
2149   virtual int argument_delta() const V8_OVERRIDE { return inputs_.length(); }
2150   HValue* argument(int i) { return OperandAt(i); }
2151
2152   virtual int OperandCount() const V8_FINAL V8_OVERRIDE {
2153     return inputs_.length();
2154   }
2155   virtual HValue* OperandAt(int i) const V8_FINAL V8_OVERRIDE {
2156     return inputs_[i];
2157   }
2158
2159   void AddInput(HValue* value);
2160
2161   DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2162
2163  protected:
2164   virtual void InternalSetOperandAt(int i, HValue* value) V8_FINAL V8_OVERRIDE {
2165     inputs_[i] = value;
2166   }
2167
2168  private:
2169   explicit HPushArguments(Zone* zone)
2170       : HInstruction(HType::Tagged()), inputs_(4, zone) {
2171     set_representation(Representation::Tagged());
2172   }
2173
2174   ZoneList<HValue*> inputs_;
2175 };
2176
2177
2178 class HThisFunction V8_FINAL : public HTemplateInstruction<0> {
2179  public:
2180   DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction);
2181
2182   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2183     return Representation::None();
2184   }
2185
2186   DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2187
2188  protected:
2189   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
2190
2191  private:
2192   HThisFunction() {
2193     set_representation(Representation::Tagged());
2194     SetFlag(kUseGVN);
2195   }
2196
2197   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2198 };
2199
2200
2201 class HDeclareGlobals V8_FINAL : public HUnaryOperation {
2202  public:
2203   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals,
2204                                               Handle<FixedArray>,
2205                                               int);
2206
2207   HValue* context() { return OperandAt(0); }
2208   Handle<FixedArray> pairs() const { return pairs_; }
2209   int flags() const { return flags_; }
2210
2211   DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2212
2213   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2214     return Representation::Tagged();
2215   }
2216
2217  private:
2218   HDeclareGlobals(HValue* context,
2219                   Handle<FixedArray> pairs,
2220                   int flags)
2221       : HUnaryOperation(context),
2222         pairs_(pairs),
2223         flags_(flags) {
2224     set_representation(Representation::Tagged());
2225     SetAllSideEffects();
2226   }
2227
2228   Handle<FixedArray> pairs_;
2229   int flags_;
2230 };
2231
2232
2233 template <int V>
2234 class HCall : public HTemplateInstruction<V> {
2235  public:
2236   // The argument count includes the receiver.
2237   explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2238     this->set_representation(Representation::Tagged());
2239     this->SetAllSideEffects();
2240   }
2241
2242   virtual HType CalculateInferredType() V8_FINAL V8_OVERRIDE {
2243     return HType::Tagged();
2244   }
2245
2246   virtual int argument_count() const {
2247     return argument_count_;
2248   }
2249
2250   virtual int argument_delta() const V8_OVERRIDE {
2251     return -argument_count();
2252   }
2253
2254  private:
2255   int argument_count_;
2256 };
2257
2258
2259 class HUnaryCall : public HCall<1> {
2260  public:
2261   HUnaryCall(HValue* value, int argument_count)
2262       : HCall<1>(argument_count) {
2263     SetOperandAt(0, value);
2264   }
2265
2266   virtual Representation RequiredInputRepresentation(
2267       int index) V8_FINAL V8_OVERRIDE {
2268     return Representation::Tagged();
2269   }
2270
2271   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2272
2273   HValue* value() const { return OperandAt(0); }
2274 };
2275
2276
2277 class HBinaryCall : public HCall<2> {
2278  public:
2279   HBinaryCall(HValue* first, HValue* second, int argument_count)
2280       : HCall<2>(argument_count) {
2281     SetOperandAt(0, first);
2282     SetOperandAt(1, second);
2283   }
2284
2285   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2286
2287   virtual Representation RequiredInputRepresentation(
2288       int index) V8_FINAL V8_OVERRIDE {
2289     return Representation::Tagged();
2290   }
2291
2292   HValue* first() const { return OperandAt(0); }
2293   HValue* second() const { return OperandAt(1); }
2294 };
2295
2296
2297 class HCallJSFunction V8_FINAL : public HCall<1> {
2298  public:
2299   static HCallJSFunction* New(Zone* zone,
2300                               HValue* context,
2301                               HValue* function,
2302                               int argument_count,
2303                               bool pass_argument_count);
2304
2305   HValue* function() const { return OperandAt(0); }
2306
2307   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2308
2309   virtual Representation RequiredInputRepresentation(
2310       int index) V8_FINAL V8_OVERRIDE {
2311     DCHECK(index == 0);
2312     return Representation::Tagged();
2313   }
2314
2315   bool pass_argument_count() const { return pass_argument_count_; }
2316
2317   virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE {
2318     return has_stack_check_;
2319   }
2320
2321   DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)
2322
2323  private:
2324   // The argument count includes the receiver.
2325   HCallJSFunction(HValue* function,
2326                   int argument_count,
2327                   bool pass_argument_count,
2328                   bool has_stack_check)
2329       : HCall<1>(argument_count),
2330         pass_argument_count_(pass_argument_count),
2331         has_stack_check_(has_stack_check) {
2332       SetOperandAt(0, function);
2333   }
2334
2335   bool pass_argument_count_;
2336   bool has_stack_check_;
2337 };
2338
2339
2340 class HCallWithDescriptor V8_FINAL : public HInstruction {
2341  public:
2342   static HCallWithDescriptor* New(Zone* zone, HValue* context,
2343       HValue* target,
2344       int argument_count,
2345       const InterfaceDescriptor* descriptor,
2346       const Vector<HValue*>& operands) {
2347     DCHECK(operands.length() == descriptor->GetEnvironmentLength());
2348     HCallWithDescriptor* res =
2349         new(zone) HCallWithDescriptor(target, argument_count,
2350                                       descriptor, operands, zone);
2351     return res;
2352   }
2353
2354   virtual int OperandCount() const V8_FINAL V8_OVERRIDE {
2355     return values_.length();
2356   }
2357   virtual HValue* OperandAt(int index) const V8_FINAL V8_OVERRIDE {
2358     return values_[index];
2359   }
2360
2361   virtual Representation RequiredInputRepresentation(
2362       int index) V8_FINAL V8_OVERRIDE {
2363     if (index == 0) {
2364       return Representation::Tagged();
2365     } else {
2366       int par_index = index - 1;
2367       DCHECK(par_index < descriptor_->GetEnvironmentLength());
2368       return descriptor_->GetParameterRepresentation(par_index);
2369     }
2370   }
2371
2372   DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2373
2374   virtual HType CalculateInferredType() V8_FINAL V8_OVERRIDE {
2375     return HType::Tagged();
2376   }
2377
2378   virtual int argument_count() const {
2379     return argument_count_;
2380   }
2381
2382   virtual int argument_delta() const V8_OVERRIDE {
2383     return -argument_count_;
2384   }
2385
2386   const InterfaceDescriptor* descriptor() const {
2387     return descriptor_;
2388   }
2389
2390   HValue* target() {
2391     return OperandAt(0);
2392   }
2393
2394   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2395
2396  private:
2397   // The argument count includes the receiver.
2398   HCallWithDescriptor(HValue* target,
2399                       int argument_count,
2400                       const InterfaceDescriptor* descriptor,
2401                       const Vector<HValue*>& operands,
2402                       Zone* zone)
2403     : descriptor_(descriptor),
2404       values_(descriptor->GetEnvironmentLength() + 1, zone) {
2405     argument_count_ = argument_count;
2406     AddOperand(target, zone);
2407     for (int i = 0; i < operands.length(); i++) {
2408       AddOperand(operands[i], zone);
2409     }
2410     this->set_representation(Representation::Tagged());
2411     this->SetAllSideEffects();
2412   }
2413
2414   void AddOperand(HValue* v, Zone* zone) {
2415     values_.Add(NULL, zone);
2416     SetOperandAt(values_.length() - 1, v);
2417   }
2418
2419   void InternalSetOperandAt(int index,
2420                             HValue* value) V8_FINAL V8_OVERRIDE {
2421     values_[index] = value;
2422   }
2423
2424   const InterfaceDescriptor* descriptor_;
2425   ZoneList<HValue*> values_;
2426   int argument_count_;
2427 };
2428
2429
2430 class HInvokeFunction V8_FINAL : public HBinaryCall {
2431  public:
2432   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int);
2433
2434   HInvokeFunction(HValue* context,
2435                   HValue* function,
2436                   Handle<JSFunction> known_function,
2437                   int argument_count)
2438       : HBinaryCall(context, function, argument_count),
2439         known_function_(known_function) {
2440     formal_parameter_count_ = known_function.is_null()
2441         ? 0 : known_function->shared()->formal_parameter_count();
2442     has_stack_check_ = !known_function.is_null() &&
2443         (known_function->code()->kind() == Code::FUNCTION ||
2444          known_function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2445   }
2446
2447   static HInvokeFunction* New(Zone* zone,
2448                               HValue* context,
2449                               HValue* function,
2450                               Handle<JSFunction> known_function,
2451                               int argument_count) {
2452     return new(zone) HInvokeFunction(context, function,
2453                                      known_function, argument_count);
2454   }
2455
2456   HValue* context() { return first(); }
2457   HValue* function() { return second(); }
2458   Handle<JSFunction> known_function() { return known_function_; }
2459   int formal_parameter_count() const { return formal_parameter_count_; }
2460
2461   virtual bool HasStackCheck() V8_FINAL V8_OVERRIDE {
2462     return has_stack_check_;
2463   }
2464
2465   DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2466
2467  private:
2468   HInvokeFunction(HValue* context, HValue* function, int argument_count)
2469       : HBinaryCall(context, function, argument_count),
2470         has_stack_check_(false) {
2471   }
2472
2473   Handle<JSFunction> known_function_;
2474   int formal_parameter_count_;
2475   bool has_stack_check_;
2476 };
2477
2478
2479 class HCallFunction V8_FINAL : public HBinaryCall {
2480  public:
2481   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int);
2482   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
2483       HCallFunction, HValue*, int, CallFunctionFlags);
2484
2485   HValue* context() { return first(); }
2486   HValue* function() { return second(); }
2487   CallFunctionFlags function_flags() const { return function_flags_; }
2488
2489   DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2490
2491   virtual int argument_delta() const V8_OVERRIDE { return -argument_count(); }
2492
2493  private:
2494   HCallFunction(HValue* context,
2495                 HValue* function,
2496                 int argument_count,
2497                 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
2498       : HBinaryCall(context, function, argument_count), function_flags_(flags) {
2499   }
2500   CallFunctionFlags function_flags_;
2501 };
2502
2503
2504 class HCallNew V8_FINAL : public HBinaryCall {
2505  public:
2506   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int);
2507
2508   HValue* context() { return first(); }
2509   HValue* constructor() { return second(); }
2510
2511   DECLARE_CONCRETE_INSTRUCTION(CallNew)
2512
2513  private:
2514   HCallNew(HValue* context, HValue* constructor, int argument_count)
2515       : HBinaryCall(context, constructor, argument_count) {}
2516 };
2517
2518
2519 class HCallNewArray V8_FINAL : public HBinaryCall {
2520  public:
2521   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallNewArray,
2522                                               HValue*,
2523                                               int,
2524                                               ElementsKind);
2525
2526   HValue* context() { return first(); }
2527   HValue* constructor() { return second(); }
2528
2529   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2530
2531   ElementsKind elements_kind() const { return elements_kind_; }
2532
2533   DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2534
2535  private:
2536   HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2537                 ElementsKind elements_kind)
2538       : HBinaryCall(context, constructor, argument_count),
2539         elements_kind_(elements_kind) {}
2540
2541   ElementsKind elements_kind_;
2542 };
2543
2544
2545 class HCallRuntime V8_FINAL : public HCall<1> {
2546  public:
2547   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCallRuntime,
2548                                               Handle<String>,
2549                                               const Runtime::Function*,
2550                                               int);
2551
2552   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2553
2554   HValue* context() { return OperandAt(0); }
2555   const Runtime::Function* function() const { return c_function_; }
2556   Handle<String> name() const { return name_; }
2557   SaveFPRegsMode save_doubles() const { return save_doubles_; }
2558   void set_save_doubles(SaveFPRegsMode save_doubles) {
2559     save_doubles_ = save_doubles;
2560   }
2561
2562   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2563     return Representation::Tagged();
2564   }
2565
2566   DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2567
2568  private:
2569   HCallRuntime(HValue* context,
2570                Handle<String> name,
2571                const Runtime::Function* c_function,
2572                int argument_count)
2573       : HCall<1>(argument_count), c_function_(c_function), name_(name),
2574         save_doubles_(kDontSaveFPRegs) {
2575     SetOperandAt(0, context);
2576   }
2577
2578   const Runtime::Function* c_function_;
2579   Handle<String> name_;
2580   SaveFPRegsMode save_doubles_;
2581 };
2582
2583
2584 class HMapEnumLength V8_FINAL : public HUnaryOperation {
2585  public:
2586   DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2587
2588   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2589     return Representation::Tagged();
2590   }
2591
2592   DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2593
2594  protected:
2595   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
2596
2597  private:
2598   explicit HMapEnumLength(HValue* value)
2599       : HUnaryOperation(value, HType::Smi()) {
2600     set_representation(Representation::Smi());
2601     SetFlag(kUseGVN);
2602     SetDependsOnFlag(kMaps);
2603   }
2604
2605   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2606 };
2607
2608
2609 class HUnaryMathOperation V8_FINAL : public HTemplateInstruction<2> {
2610  public:
2611   static HInstruction* New(Zone* zone,
2612                            HValue* context,
2613                            HValue* value,
2614                            BuiltinFunctionId op);
2615
2616   HValue* context() const { return OperandAt(0); }
2617   HValue* value() const { return OperandAt(1); }
2618
2619   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2620
2621   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2622     if (index == 0) {
2623       return Representation::Tagged();
2624     } else {
2625       switch (op_) {
2626         case kMathFloor:
2627         case kMathRound:
2628         case kMathFround:
2629         case kMathSqrt:
2630         case kMathPowHalf:
2631         case kMathLog:
2632         case kMathExp:
2633           return Representation::Double();
2634         case kMathAbs:
2635           return representation();
2636         case kMathClz32:
2637           return Representation::Integer32();
2638         default:
2639           UNREACHABLE();
2640           return Representation::None();
2641       }
2642     }
2643   }
2644
2645   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
2646
2647   virtual HValue* Canonicalize() V8_OVERRIDE;
2648   virtual Representation RepresentationFromUses() V8_OVERRIDE;
2649   virtual Representation RepresentationFromInputs() V8_OVERRIDE;
2650
2651   BuiltinFunctionId op() const { return op_; }
2652   const char* OpName() const;
2653
2654   DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2655
2656  protected:
2657   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2658     HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2659     return op_ == b->op();
2660   }
2661
2662  private:
2663   // Indicates if we support a double (and int32) output for Math.floor and
2664   // Math.round.
2665   bool SupportsFlexibleFloorAndRound() const {
2666 #ifdef V8_TARGET_ARCH_ARM64
2667     return true;
2668 #else
2669     return false;
2670 #endif
2671   }
2672   HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2673       : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2674     SetOperandAt(0, context);
2675     SetOperandAt(1, value);
2676     switch (op) {
2677       case kMathFloor:
2678       case kMathRound:
2679         if (SupportsFlexibleFloorAndRound()) {
2680           SetFlag(kFlexibleRepresentation);
2681         } else {
2682           set_representation(Representation::Integer32());
2683         }
2684         break;
2685       case kMathClz32:
2686         set_representation(Representation::Integer32());
2687         break;
2688       case kMathAbs:
2689         // Not setting representation here: it is None intentionally.
2690         SetFlag(kFlexibleRepresentation);
2691         // TODO(svenpanne) This flag is actually only needed if representation()
2692         // is tagged, and not when it is an unboxed double or unboxed integer.
2693         SetChangesFlag(kNewSpacePromotion);
2694         break;
2695       case kMathFround:
2696       case kMathLog:
2697       case kMathExp:
2698       case kMathSqrt:
2699       case kMathPowHalf:
2700         set_representation(Representation::Double());
2701         break;
2702       default:
2703         UNREACHABLE();
2704     }
2705     SetFlag(kUseGVN);
2706     SetFlag(kAllowUndefinedAsNaN);
2707   }
2708
2709   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2710
2711   HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2712   HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2713
2714   BuiltinFunctionId op_;
2715 };
2716
2717
2718 class HLoadRoot V8_FINAL : public HTemplateInstruction<0> {
2719  public:
2720   DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2721   DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2722
2723   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2724     return Representation::None();
2725   }
2726
2727   Heap::RootListIndex index() const { return index_; }
2728
2729   DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2730
2731  protected:
2732   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2733     HLoadRoot* b = HLoadRoot::cast(other);
2734     return index_ == b->index_;
2735   }
2736
2737  private:
2738   explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2739       : HTemplateInstruction<0>(type), index_(index) {
2740     SetFlag(kUseGVN);
2741     // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2742     // corresponding HStoreRoot instruction.
2743     SetDependsOnFlag(kCalls);
2744   }
2745
2746   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
2747
2748   const Heap::RootListIndex index_;
2749 };
2750
2751
2752 class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
2753  public:
2754   static HCheckMaps* New(Zone* zone, HValue* context, HValue* value,
2755                          Handle<Map> map, HValue* typecheck = NULL) {
2756     return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2757             Unique<Map>::CreateImmovable(map), zone), typecheck);
2758   }
2759   static HCheckMaps* New(Zone* zone, HValue* context,
2760                          HValue* value, SmallMapList* map_list,
2761                          HValue* typecheck = NULL) {
2762     UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2763     for (int i = 0; i < map_list->length(); ++i) {
2764       maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2765     }
2766     return new(zone) HCheckMaps(value, maps, typecheck);
2767   }
2768
2769   bool IsStabilityCheck() const { return is_stability_check_; }
2770   void MarkAsStabilityCheck() {
2771     maps_are_stable_ = true;
2772     has_migration_target_ = false;
2773     is_stability_check_ = true;
2774     ClearChangesFlag(kNewSpacePromotion);
2775     ClearDependsOnFlag(kElementsKind);
2776     ClearDependsOnFlag(kMaps);
2777   }
2778
2779   virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
2780   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2781     return Representation::Tagged();
2782   }
2783
2784   virtual HType CalculateInferredType() V8_OVERRIDE {
2785     if (value()->type().IsHeapObject()) return value()->type();
2786     return HType::HeapObject();
2787   }
2788
2789   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2790
2791   HValue* value() const { return OperandAt(0); }
2792   HValue* typecheck() const { return OperandAt(1); }
2793
2794   const UniqueSet<Map>* maps() const { return maps_; }
2795   void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2796
2797   bool maps_are_stable() const { return maps_are_stable_; }
2798
2799   bool HasMigrationTarget() const { return has_migration_target_; }
2800
2801   virtual HValue* Canonicalize() V8_OVERRIDE;
2802
2803   static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2804                                           HValue* value,
2805                                           Unique<Map> map,
2806                                           bool map_is_stable,
2807                                           HInstruction* instr) {
2808     return instr->Append(new(zone) HCheckMaps(
2809             value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2810   }
2811
2812   static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2813                                            HValue* value,
2814                                            const UniqueSet<Map>* maps,
2815                                            bool maps_are_stable,
2816                                            HInstruction* instr) {
2817     return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2818   }
2819
2820   DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2821
2822  protected:
2823   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2824     return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2825   }
2826
2827   virtual int RedefinedOperandIndex() { return 0; }
2828
2829  private:
2830   HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2831       : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2832         has_migration_target_(false), is_stability_check_(false),
2833         maps_are_stable_(maps_are_stable) {
2834     DCHECK_NE(0, maps->size());
2835     SetOperandAt(0, value);
2836     // Use the object value for the dependency.
2837     SetOperandAt(1, value);
2838     set_representation(Representation::Tagged());
2839     SetFlag(kUseGVN);
2840     SetDependsOnFlag(kMaps);
2841     SetDependsOnFlag(kElementsKind);
2842   }
2843
2844   HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2845       : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
2846         has_migration_target_(false), is_stability_check_(false),
2847         maps_are_stable_(true) {
2848     DCHECK_NE(0, maps->size());
2849     SetOperandAt(0, value);
2850     // Use the object value for the dependency if NULL is passed.
2851     SetOperandAt(1, typecheck ? typecheck : value);
2852     set_representation(Representation::Tagged());
2853     SetFlag(kUseGVN);
2854     SetDependsOnFlag(kMaps);
2855     SetDependsOnFlag(kElementsKind);
2856     for (int i = 0; i < maps->size(); ++i) {
2857       Handle<Map> map = maps->at(i).handle();
2858       if (map->is_migration_target()) has_migration_target_ = true;
2859       if (!map->is_stable()) maps_are_stable_ = false;
2860     }
2861     if (has_migration_target_) SetChangesFlag(kNewSpacePromotion);
2862   }
2863
2864   const UniqueSet<Map>* maps_;
2865   bool has_migration_target_ : 1;
2866   bool is_stability_check_ : 1;
2867   bool maps_are_stable_ : 1;
2868 };
2869
2870
2871 class HCheckValue V8_FINAL : public HUnaryOperation {
2872  public:
2873   static HCheckValue* New(Zone* zone, HValue* context,
2874                           HValue* value, Handle<JSFunction> func) {
2875     bool in_new_space = zone->isolate()->heap()->InNewSpace(*func);
2876     // NOTE: We create an uninitialized Unique and initialize it later.
2877     // This is because a JSFunction can move due to GC during graph creation.
2878     // TODO(titzer): This is a migration crutch. Replace with some kind of
2879     // Uniqueness scope later.
2880     Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2881     HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2882     return check;
2883   }
2884   static HCheckValue* New(Zone* zone, HValue* context,
2885                           HValue* value, Unique<HeapObject> target,
2886                           bool object_in_new_space) {
2887     return new(zone) HCheckValue(value, target, object_in_new_space);
2888   }
2889
2890   virtual void FinalizeUniqueness() V8_OVERRIDE {
2891     object_ = Unique<HeapObject>(object_.handle());
2892   }
2893
2894   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2895     return Representation::Tagged();
2896   }
2897   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2898
2899   virtual HValue* Canonicalize() V8_OVERRIDE;
2900
2901 #ifdef DEBUG
2902   virtual void Verify() V8_OVERRIDE;
2903 #endif
2904
2905   Unique<HeapObject> object() const { return object_; }
2906   bool object_in_new_space() const { return object_in_new_space_; }
2907
2908   DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2909
2910  protected:
2911   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2912     HCheckValue* b = HCheckValue::cast(other);
2913     return object_ == b->object_;
2914   }
2915
2916  private:
2917   HCheckValue(HValue* value, Unique<HeapObject> object,
2918                bool object_in_new_space)
2919       : HUnaryOperation(value, value->type()),
2920         object_(object),
2921         object_in_new_space_(object_in_new_space) {
2922     set_representation(Representation::Tagged());
2923     SetFlag(kUseGVN);
2924   }
2925
2926   Unique<HeapObject> object_;
2927   bool object_in_new_space_;
2928 };
2929
2930
2931 class HCheckInstanceType V8_FINAL : public HUnaryOperation {
2932  public:
2933   enum Check {
2934     IS_SPEC_OBJECT,
2935     IS_JS_ARRAY,
2936     IS_STRING,
2937     IS_INTERNALIZED_STRING,
2938     LAST_INTERVAL_CHECK = IS_JS_ARRAY
2939   };
2940
2941   DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2942
2943   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
2944
2945   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2946     return Representation::Tagged();
2947   }
2948
2949   virtual HType CalculateInferredType() V8_OVERRIDE {
2950     switch (check_) {
2951       case IS_SPEC_OBJECT: return HType::JSObject();
2952       case IS_JS_ARRAY: return HType::JSArray();
2953       case IS_STRING: return HType::String();
2954       case IS_INTERNALIZED_STRING: return HType::String();
2955     }
2956     UNREACHABLE();
2957     return HType::Tagged();
2958   }
2959
2960   virtual HValue* Canonicalize() V8_OVERRIDE;
2961
2962   bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2963   void GetCheckInterval(InstanceType* first, InstanceType* last);
2964   void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2965
2966   Check check() const { return check_; }
2967
2968   DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2969
2970  protected:
2971   // TODO(ager): It could be nice to allow the ommision of instance
2972   // type checks if we have already performed an instance type check
2973   // with a larger range.
2974   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
2975     HCheckInstanceType* b = HCheckInstanceType::cast(other);
2976     return check_ == b->check_;
2977   }
2978
2979   virtual int RedefinedOperandIndex() { return 0; }
2980
2981  private:
2982   const char* GetCheckName() const;
2983
2984   HCheckInstanceType(HValue* value, Check check)
2985       : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2986     set_representation(Representation::Tagged());
2987     SetFlag(kUseGVN);
2988   }
2989
2990   const Check check_;
2991 };
2992
2993
2994 class HCheckSmi V8_FINAL : public HUnaryOperation {
2995  public:
2996   DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2997
2998   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
2999     return Representation::Tagged();
3000   }
3001
3002   virtual HValue* Canonicalize() V8_OVERRIDE {
3003     HType value_type = value()->type();
3004     if (value_type.IsSmi()) {
3005       return NULL;
3006     }
3007     return this;
3008   }
3009
3010   DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
3011
3012  protected:
3013   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3014
3015  private:
3016   explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
3017     set_representation(Representation::Smi());
3018     SetFlag(kUseGVN);
3019   }
3020 };
3021
3022
3023 class HCheckHeapObject V8_FINAL : public HUnaryOperation {
3024  public:
3025   DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
3026
3027   virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
3028   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3029     return Representation::Tagged();
3030   }
3031
3032   virtual HType CalculateInferredType() V8_OVERRIDE {
3033     if (value()->type().IsHeapObject()) return value()->type();
3034     return HType::HeapObject();
3035   }
3036
3037 #ifdef DEBUG
3038   virtual void Verify() V8_OVERRIDE;
3039 #endif
3040
3041   virtual HValue* Canonicalize() V8_OVERRIDE {
3042     return value()->type().IsHeapObject() ? NULL : this;
3043   }
3044
3045   DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3046
3047  protected:
3048   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3049
3050  private:
3051   explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3052     set_representation(Representation::Tagged());
3053     SetFlag(kUseGVN);
3054   }
3055 };
3056
3057
3058 class InductionVariableData;
3059
3060
3061 struct InductionVariableLimitUpdate {
3062   InductionVariableData* updated_variable;
3063   HValue* limit;
3064   bool limit_is_upper;
3065   bool limit_is_included;
3066
3067   InductionVariableLimitUpdate()
3068       : updated_variable(NULL), limit(NULL),
3069         limit_is_upper(false), limit_is_included(false) {}
3070 };
3071
3072
3073 class HBoundsCheck;
3074 class HPhi;
3075 class HConstant;
3076 class HBitwise;
3077
3078
3079 class InductionVariableData V8_FINAL : public ZoneObject {
3080  public:
3081   class InductionVariableCheck : public ZoneObject {
3082    public:
3083     HBoundsCheck* check() { return check_; }
3084     InductionVariableCheck* next() { return next_; }
3085     bool HasUpperLimit() { return upper_limit_ >= 0; }
3086     int32_t upper_limit() {
3087       DCHECK(HasUpperLimit());
3088       return upper_limit_;
3089     }
3090     void set_upper_limit(int32_t upper_limit) {
3091       upper_limit_ = upper_limit;
3092     }
3093
3094     bool processed() { return processed_; }
3095     void set_processed() { processed_ = true; }
3096
3097     InductionVariableCheck(HBoundsCheck* check,
3098                            InductionVariableCheck* next,
3099                            int32_t upper_limit = kNoLimit)
3100         : check_(check), next_(next), upper_limit_(upper_limit),
3101           processed_(false) {}
3102
3103    private:
3104     HBoundsCheck* check_;
3105     InductionVariableCheck* next_;
3106     int32_t upper_limit_;
3107     bool processed_;
3108   };
3109
3110   class ChecksRelatedToLength : public ZoneObject {
3111    public:
3112     HValue* length() { return length_; }
3113     ChecksRelatedToLength* next() { return next_; }
3114     InductionVariableCheck* checks() { return checks_; }
3115
3116     void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3117     void CloseCurrentBlock();
3118
3119     ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3120       : length_(length), next_(next), checks_(NULL),
3121         first_check_in_block_(NULL),
3122         added_index_(NULL),
3123         added_constant_(NULL),
3124         current_and_mask_in_block_(0),
3125         current_or_mask_in_block_(0) {}
3126
3127    private:
3128     void UseNewIndexInCurrentBlock(Token::Value token,
3129                                    int32_t mask,
3130                                    HValue* index_base,
3131                                    HValue* context);
3132
3133     HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
3134     HBitwise* added_index() { return added_index_; }
3135     void set_added_index(HBitwise* index) { added_index_ = index; }
3136     HConstant* added_constant() { return added_constant_; }
3137     void set_added_constant(HConstant* constant) { added_constant_ = constant; }
3138     int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
3139     int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
3140     int32_t current_upper_limit() { return current_upper_limit_; }
3141
3142     HValue* length_;
3143     ChecksRelatedToLength* next_;
3144     InductionVariableCheck* checks_;
3145
3146     HBoundsCheck* first_check_in_block_;
3147     HBitwise* added_index_;
3148     HConstant* added_constant_;
3149     int32_t current_and_mask_in_block_;
3150     int32_t current_or_mask_in_block_;
3151     int32_t current_upper_limit_;
3152   };
3153
3154   struct LimitFromPredecessorBlock {
3155     InductionVariableData* variable;
3156     Token::Value token;
3157     HValue* limit;
3158     HBasicBlock* other_target;
3159
3160     bool LimitIsValid() { return token != Token::ILLEGAL; }
3161
3162     bool LimitIsIncluded() {
3163       return Token::IsEqualityOp(token) ||
3164           token == Token::GTE || token == Token::LTE;
3165     }
3166     bool LimitIsUpper() {
3167       return token == Token::LTE || token == Token::LT || token == Token::NE;
3168     }
3169
3170     LimitFromPredecessorBlock()
3171         : variable(NULL),
3172           token(Token::ILLEGAL),
3173           limit(NULL),
3174           other_target(NULL) {}
3175   };
3176
3177   static const int32_t kNoLimit = -1;
3178
3179   static InductionVariableData* ExaminePhi(HPhi* phi);
3180   static void ComputeLimitFromPredecessorBlock(
3181       HBasicBlock* block,
3182       LimitFromPredecessorBlock* result);
3183   static bool ComputeInductionVariableLimit(
3184       HBasicBlock* block,
3185       InductionVariableLimitUpdate* additional_limit);
3186
3187   struct BitwiseDecompositionResult {
3188     HValue* base;
3189     int32_t and_mask;
3190     int32_t or_mask;
3191     HValue* context;
3192
3193     BitwiseDecompositionResult()
3194         : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3195   };
3196   static void DecomposeBitwise(HValue* value,
3197                                BitwiseDecompositionResult* result);
3198
3199   void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3200
3201   bool CheckIfBranchIsLoopGuard(Token::Value token,
3202                                 HBasicBlock* current_branch,
3203                                 HBasicBlock* other_branch);
3204
3205   void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3206
3207   HPhi* phi() { return phi_; }
3208   HValue* base() { return base_; }
3209   int32_t increment() { return increment_; }
3210   HValue* limit() { return limit_; }
3211   bool limit_included() { return limit_included_; }
3212   HBasicBlock* limit_validity() { return limit_validity_; }
3213   HBasicBlock* induction_exit_block() { return induction_exit_block_; }
3214   HBasicBlock* induction_exit_target() { return induction_exit_target_; }
3215   ChecksRelatedToLength* checks() { return checks_; }
3216   HValue* additional_upper_limit() { return additional_upper_limit_; }
3217   bool additional_upper_limit_is_included() {
3218     return additional_upper_limit_is_included_;
3219   }
3220   HValue* additional_lower_limit() { return additional_lower_limit_; }
3221   bool additional_lower_limit_is_included() {
3222     return additional_lower_limit_is_included_;
3223   }
3224
3225   bool LowerLimitIsNonNegativeConstant() {
3226     if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3227       return true;
3228     }
3229     if (additional_lower_limit() != NULL &&
3230         additional_lower_limit()->IsInteger32Constant() &&
3231         additional_lower_limit()->GetInteger32Constant() >= 0) {
3232       // Ignoring the corner case of !additional_lower_limit_is_included()
3233       // is safe, handling it adds unneeded complexity.
3234       return true;
3235     }
3236     return false;
3237   }
3238
3239   int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3240
3241  private:
3242   template <class T> void swap(T* a, T* b) {
3243     T c(*a);
3244     *a = *b;
3245     *b = c;
3246   }
3247
3248   InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3249       : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3250         limit_(NULL), limit_included_(false), limit_validity_(NULL),
3251         induction_exit_block_(NULL), induction_exit_target_(NULL),
3252         checks_(NULL),
3253         additional_upper_limit_(NULL),
3254         additional_upper_limit_is_included_(false),
3255         additional_lower_limit_(NULL),
3256         additional_lower_limit_is_included_(false) {}
3257
3258   static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3259
3260   static HValue* IgnoreOsrValue(HValue* v);
3261   static InductionVariableData* GetInductionVariableData(HValue* v);
3262
3263   HPhi* phi_;
3264   HValue* base_;
3265   int32_t increment_;
3266   HValue* limit_;
3267   bool limit_included_;
3268   HBasicBlock* limit_validity_;
3269   HBasicBlock* induction_exit_block_;
3270   HBasicBlock* induction_exit_target_;
3271   ChecksRelatedToLength* checks_;
3272   HValue* additional_upper_limit_;
3273   bool additional_upper_limit_is_included_;
3274   HValue* additional_lower_limit_;
3275   bool additional_lower_limit_is_included_;
3276 };
3277
3278
3279 class HPhi V8_FINAL : public HValue {
3280  public:
3281   HPhi(int merged_index, Zone* zone)
3282       : inputs_(2, zone),
3283         merged_index_(merged_index),
3284         phi_id_(-1),
3285         induction_variable_data_(NULL) {
3286     for (int i = 0; i < Representation::kNumRepresentations; i++) {
3287       non_phi_uses_[i] = 0;
3288       indirect_uses_[i] = 0;
3289     }
3290     DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3291     SetFlag(kFlexibleRepresentation);
3292     SetFlag(kAllowUndefinedAsNaN);
3293   }
3294
3295   virtual Representation RepresentationFromInputs() V8_OVERRIDE;
3296
3297   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
3298   virtual void InferRepresentation(
3299       HInferRepresentationPhase* h_infer) V8_OVERRIDE;
3300   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3301     return representation();
3302   }
3303   virtual Representation KnownOptimalRepresentation() V8_OVERRIDE {
3304     return representation();
3305   }
3306   virtual HType CalculateInferredType() V8_OVERRIDE;
3307   virtual int OperandCount() const V8_OVERRIDE { return inputs_.length(); }
3308   virtual HValue* OperandAt(int index) const V8_OVERRIDE {
3309     return inputs_[index];
3310   }
3311   HValue* GetRedundantReplacement();
3312   void AddInput(HValue* value);
3313   bool HasRealUses();
3314
3315   bool IsReceiver() const { return merged_index_ == 0; }
3316   bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3317
3318   virtual HSourcePosition position() const V8_OVERRIDE;
3319
3320   int merged_index() const { return merged_index_; }
3321
3322   InductionVariableData* induction_variable_data() {
3323     return induction_variable_data_;
3324   }
3325   bool IsInductionVariable() {
3326     return induction_variable_data_ != NULL;
3327   }
3328   bool IsLimitedInductionVariable() {
3329     return IsInductionVariable() &&
3330         induction_variable_data_->limit() != NULL;
3331   }
3332   void DetectInductionVariable() {
3333     DCHECK(induction_variable_data_ == NULL);
3334     induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3335   }
3336
3337   virtual OStream& PrintTo(OStream& os) const V8_OVERRIDE;  // NOLINT
3338
3339 #ifdef DEBUG
3340   virtual void Verify() V8_OVERRIDE;
3341 #endif
3342
3343   void InitRealUses(int id);
3344   void AddNonPhiUsesFrom(HPhi* other);
3345   void AddIndirectUsesTo(int* use_count);
3346
3347   int tagged_non_phi_uses() const {
3348     return non_phi_uses_[Representation::kTagged];
3349   }
3350   int smi_non_phi_uses() const {
3351     return non_phi_uses_[Representation::kSmi];
3352   }
3353   int int32_non_phi_uses() const {
3354     return non_phi_uses_[Representation::kInteger32];
3355   }
3356   int double_non_phi_uses() const {
3357     return non_phi_uses_[Representation::kDouble];
3358   }
3359   int tagged_indirect_uses() const {
3360     return indirect_uses_[Representation::kTagged];
3361   }
3362   int smi_indirect_uses() const {
3363     return indirect_uses_[Representation::kSmi];
3364   }
3365   int int32_indirect_uses() const {
3366     return indirect_uses_[Representation::kInteger32];
3367   }
3368   int double_indirect_uses() const {
3369     return indirect_uses_[Representation::kDouble];
3370   }
3371   int phi_id() { return phi_id_; }
3372
3373   static HPhi* cast(HValue* value) {
3374     DCHECK(value->IsPhi());
3375     return reinterpret_cast<HPhi*>(value);
3376   }
3377   virtual Opcode opcode() const V8_OVERRIDE { return HValue::kPhi; }
3378
3379   void SimplifyConstantInputs();
3380
3381   // Marker value representing an invalid merge index.
3382   static const int kInvalidMergedIndex = -1;
3383
3384  protected:
3385   virtual void DeleteFromGraph() V8_OVERRIDE;
3386   virtual void InternalSetOperandAt(int index, HValue* value) V8_OVERRIDE {
3387     inputs_[index] = value;
3388   }
3389
3390  private:
3391   ZoneList<HValue*> inputs_;
3392   int merged_index_;
3393
3394   int non_phi_uses_[Representation::kNumRepresentations];
3395   int indirect_uses_[Representation::kNumRepresentations];
3396   int phi_id_;
3397   InductionVariableData* induction_variable_data_;
3398
3399   // TODO(titzer): we can't eliminate the receiver for generating backtraces
3400   virtual bool IsDeletable() const V8_OVERRIDE { return !IsReceiver(); }
3401 };
3402
3403
3404 // Common base class for HArgumentsObject and HCapturedObject.
3405 class HDematerializedObject : public HInstruction {
3406  public:
3407   HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3408
3409   virtual int OperandCount() const V8_FINAL V8_OVERRIDE {
3410     return values_.length();
3411   }
3412   virtual HValue* OperandAt(int index) const V8_FINAL V8_OVERRIDE {
3413     return values_[index];
3414   }
3415
3416   virtual bool HasEscapingOperandAt(int index) V8_FINAL V8_OVERRIDE {
3417     return false;
3418   }
3419   virtual Representation RequiredInputRepresentation(
3420       int index) V8_FINAL V8_OVERRIDE {
3421     return Representation::None();
3422   }
3423
3424  protected:
3425   virtual void InternalSetOperandAt(int index,
3426                                     HValue* value) V8_FINAL V8_OVERRIDE {
3427     values_[index] = value;
3428   }
3429
3430   // List of values tracked by this marker.
3431   ZoneList<HValue*> values_;
3432 };
3433
3434
3435 class HArgumentsObject V8_FINAL : public HDematerializedObject {
3436  public:
3437   static HArgumentsObject* New(Zone* zone, HValue* context, int count) {
3438     return new(zone) HArgumentsObject(count, zone);
3439   }
3440
3441   // The values contain a list of all elements in the arguments object
3442   // including the receiver object, which is skipped when materializing.
3443   const ZoneList<HValue*>* arguments_values() const { return &values_; }
3444   int arguments_count() const { return values_.length(); }
3445
3446   void AddArgument(HValue* argument, Zone* zone) {
3447     values_.Add(NULL, zone);  // Resize list.
3448     SetOperandAt(values_.length() - 1, argument);
3449   }
3450
3451   DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3452
3453  private:
3454   HArgumentsObject(int count, Zone* zone)
3455       : HDematerializedObject(count, zone) {
3456     set_representation(Representation::Tagged());
3457     SetFlag(kIsArguments);
3458   }
3459 };
3460
3461
3462 class HCapturedObject V8_FINAL : public HDematerializedObject {
3463  public:
3464   HCapturedObject(int length, int id, Zone* zone)
3465       : HDematerializedObject(length, zone), capture_id_(id) {
3466     set_representation(Representation::Tagged());
3467     values_.AddBlock(NULL, length, zone);  // Resize list.
3468   }
3469
3470   // The values contain a list of all in-object properties inside the
3471   // captured object and is index by field index. Properties in the
3472   // properties or elements backing store are not tracked here.
3473   const ZoneList<HValue*>* values() const { return &values_; }
3474   int length() const { return values_.length(); }
3475   int capture_id() const { return capture_id_; }
3476
3477   // Shortcut for the map value of this captured object.
3478   HValue* map_value() const { return values()->first(); }
3479
3480   void ReuseSideEffectsFromStore(HInstruction* store) {
3481     DCHECK(store->HasObservableSideEffects());
3482     DCHECK(store->IsStoreNamedField());
3483     changes_flags_.Add(store->ChangesFlags());
3484   }
3485
3486   // Replay effects of this instruction on the given environment.
3487   void ReplayEnvironment(HEnvironment* env);
3488
3489   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
3490
3491   DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3492
3493  private:
3494   int capture_id_;
3495
3496   // Note that we cannot DCE captured objects as they are used to replay
3497   // the environment. This method is here as an explicit reminder.
3498   // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3499   virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return false; }
3500 };
3501
3502
3503 class HConstant V8_FINAL : public HTemplateInstruction<0> {
3504  public:
3505   DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3506   DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3507   DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3508   DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3509   DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3510
3511   static HConstant* CreateAndInsertAfter(Zone* zone,
3512                                          HValue* context,
3513                                          int32_t value,
3514                                          Representation representation,
3515                                          HInstruction* instruction) {
3516     return instruction->Append(HConstant::New(
3517         zone, context, value, representation));
3518   }
3519
3520   static HConstant* CreateAndInsertBefore(Zone* zone,
3521                                           HValue* context,
3522                                           int32_t value,
3523                                           Representation representation,
3524                                           HInstruction* instruction) {
3525     return instruction->Prepend(HConstant::New(
3526         zone, context, value, representation));
3527   }
3528
3529   static HConstant* CreateAndInsertBefore(Zone* zone,
3530                                           Unique<Map> map,
3531                                           bool map_is_stable,
3532                                           HInstruction* instruction) {
3533     return instruction->Prepend(new(zone) HConstant(
3534         map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3535         Representation::Tagged(), HType::HeapObject(), true,
3536         false, false, MAP_TYPE));
3537   }
3538
3539   static HConstant* CreateAndInsertAfter(Zone* zone,
3540                                          Unique<Map> map,
3541                                          bool map_is_stable,
3542                                          HInstruction* instruction) {
3543     return instruction->Append(new(zone) HConstant(
3544             map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3545             Representation::Tagged(), HType::HeapObject(), true,
3546             false, false, MAP_TYPE));
3547   }
3548
3549   Handle<Object> handle(Isolate* isolate) {
3550     if (object_.handle().is_null()) {
3551       // Default arguments to is_not_in_new_space depend on this heap number
3552       // to be tenured so that it's guaranteed not to be located in new space.
3553       object_ = Unique<Object>::CreateUninitialized(
3554           isolate->factory()->NewNumber(double_value_, TENURED));
3555     }
3556     AllowDeferredHandleDereference smi_check;
3557     DCHECK(has_int32_value_ || !object_.handle()->IsSmi());
3558     return object_.handle();
3559   }
3560
3561   bool IsSpecialDouble() const {
3562     return has_double_value_ &&
3563         (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) ||
3564          FixedDoubleArray::is_the_hole_nan(double_value_) ||
3565          std::isnan(double_value_));
3566   }
3567
3568   bool NotInNewSpace() const {
3569     return is_not_in_new_space_;
3570   }
3571
3572   bool ImmortalImmovable() const;
3573
3574   bool IsCell() const {
3575     return instance_type_ == CELL_TYPE || instance_type_ == PROPERTY_CELL_TYPE;
3576   }
3577
3578   bool IsMap() const {
3579     return instance_type_ == MAP_TYPE;
3580   }
3581
3582   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3583     return Representation::None();
3584   }
3585
3586   virtual Representation KnownOptimalRepresentation() V8_OVERRIDE {
3587     if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3588     if (HasInteger32Value()) return Representation::Integer32();
3589     if (HasNumberValue()) return Representation::Double();
3590     if (HasExternalReferenceValue()) return Representation::External();
3591     return Representation::Tagged();
3592   }
3593
3594   virtual bool EmitAtUses() V8_OVERRIDE;
3595   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
3596   HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3597   Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3598   Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone);
3599   bool HasInteger32Value() const { return has_int32_value_; }
3600   int32_t Integer32Value() const {
3601     DCHECK(HasInteger32Value());
3602     return int32_value_;
3603   }
3604   bool HasSmiValue() const { return has_smi_value_; }
3605   bool HasDoubleValue() const { return has_double_value_; }
3606   double DoubleValue() const {
3607     DCHECK(HasDoubleValue());
3608     return double_value_;
3609   }
3610   bool IsTheHole() const {
3611     if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) {
3612       return true;
3613     }
3614     return object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3615   }
3616   bool HasNumberValue() const { return has_double_value_; }
3617   int32_t NumberValueAsInteger32() const {
3618     DCHECK(HasNumberValue());
3619     // Irrespective of whether a numeric HConstant can be safely
3620     // represented as an int32, we store the (in some cases lossy)
3621     // representation of the number in int32_value_.
3622     return int32_value_;
3623   }
3624   bool HasStringValue() const {
3625     if (has_double_value_ || has_int32_value_) return false;
3626     DCHECK(!object_.handle().is_null());
3627     return instance_type_ < FIRST_NONSTRING_TYPE;
3628   }
3629   Handle<String> StringValue() const {
3630     DCHECK(HasStringValue());
3631     return Handle<String>::cast(object_.handle());
3632   }
3633   bool HasInternalizedStringValue() const {
3634     return HasStringValue() && StringShape(instance_type_).IsInternalized();
3635   }
3636
3637   bool HasExternalReferenceValue() const {
3638     return has_external_reference_value_;
3639   }
3640   ExternalReference ExternalReferenceValue() const {
3641     return external_reference_value_;
3642   }
3643
3644   bool HasBooleanValue() const { return type_.IsBoolean(); }
3645   bool BooleanValue() const { return boolean_value_; }
3646   bool IsUndetectable() const { return is_undetectable_; }
3647   InstanceType GetInstanceType() const { return instance_type_; }
3648
3649   bool HasMapValue() const { return instance_type_ == MAP_TYPE; }
3650   Unique<Map> MapValue() const {
3651     DCHECK(HasMapValue());
3652     return Unique<Map>::cast(GetUnique());
3653   }
3654   bool HasStableMapValue() const {
3655     DCHECK(HasMapValue() || !has_stable_map_value_);
3656     return has_stable_map_value_;
3657   }
3658
3659   bool HasObjectMap() const { return !object_map_.IsNull(); }
3660   Unique<Map> ObjectMap() const {
3661     DCHECK(HasObjectMap());
3662     return object_map_;
3663   }
3664
3665   virtual intptr_t Hashcode() V8_OVERRIDE {
3666     if (has_int32_value_) {
3667       return static_cast<intptr_t>(int32_value_);
3668     } else if (has_double_value_) {
3669       return static_cast<intptr_t>(BitCast<int64_t>(double_value_));
3670     } else if (has_external_reference_value_) {
3671       return reinterpret_cast<intptr_t>(external_reference_value_.address());
3672     } else {
3673       DCHECK(!object_.handle().is_null());
3674       return object_.Hashcode();
3675     }
3676   }
3677
3678   virtual void FinalizeUniqueness() V8_OVERRIDE {
3679     if (!has_double_value_ && !has_external_reference_value_) {
3680       DCHECK(!object_.handle().is_null());
3681       object_ = Unique<Object>(object_.handle());
3682     }
3683   }
3684
3685   Unique<Object> GetUnique() const {
3686     return object_;
3687   }
3688
3689   bool EqualsUnique(Unique<Object> other) const {
3690     return object_.IsInitialized() && object_ == other;
3691   }
3692
3693   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
3694     HConstant* other_constant = HConstant::cast(other);
3695     if (has_int32_value_) {
3696       return other_constant->has_int32_value_ &&
3697           int32_value_ == other_constant->int32_value_;
3698     } else if (has_double_value_) {
3699       return other_constant->has_double_value_ &&
3700           BitCast<int64_t>(double_value_) ==
3701           BitCast<int64_t>(other_constant->double_value_);
3702     } else if (has_external_reference_value_) {
3703       return other_constant->has_external_reference_value_ &&
3704           external_reference_value_ ==
3705           other_constant->external_reference_value_;
3706     } else {
3707       if (other_constant->has_int32_value_ ||
3708           other_constant->has_double_value_ ||
3709           other_constant->has_external_reference_value_) {
3710         return false;
3711       }
3712       DCHECK(!object_.handle().is_null());
3713       return other_constant->object_ == object_;
3714     }
3715   }
3716
3717 #ifdef DEBUG
3718   virtual void Verify() V8_OVERRIDE { }
3719 #endif
3720
3721   DECLARE_CONCRETE_INSTRUCTION(Constant)
3722
3723  protected:
3724   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
3725
3726  private:
3727   friend class HGraph;
3728   explicit HConstant(Handle<Object> handle,
3729                      Representation r = Representation::None());
3730   HConstant(int32_t value,
3731             Representation r = Representation::None(),
3732             bool is_not_in_new_space = true,
3733             Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3734   HConstant(double value,
3735             Representation r = Representation::None(),
3736             bool is_not_in_new_space = true,
3737             Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3738   HConstant(Unique<Object> object,
3739             Unique<Map> object_map,
3740             bool has_stable_map_value,
3741             Representation r,
3742             HType type,
3743             bool is_not_in_new_space,
3744             bool boolean_value,
3745             bool is_undetectable,
3746             InstanceType instance_type);
3747
3748   explicit HConstant(ExternalReference reference);
3749
3750   void Initialize(Representation r);
3751
3752   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
3753
3754   // If this is a numerical constant, object_ either points to the
3755   // HeapObject the constant originated from or is null.  If the
3756   // constant is non-numeric, object_ always points to a valid
3757   // constant HeapObject.
3758   Unique<Object> object_;
3759
3760   // If object_ is a heap object, this points to the stable map of the object.
3761   Unique<Map> object_map_;
3762
3763   // If object_ is a map, this indicates whether the map is stable.
3764   bool has_stable_map_value_ : 1;
3765
3766   // We store the HConstant in the most specific form safely possible.
3767   // The two flags, has_int32_value_ and has_double_value_ tell us if
3768   // int32_value_ and double_value_ hold valid, safe representations
3769   // of the constant.  has_int32_value_ implies has_double_value_ but
3770   // not the converse.
3771   bool has_smi_value_ : 1;
3772   bool has_int32_value_ : 1;
3773   bool has_double_value_ : 1;
3774   bool has_external_reference_value_ : 1;
3775   bool is_not_in_new_space_ : 1;
3776   bool boolean_value_ : 1;
3777   bool is_undetectable_: 1;
3778   int32_t int32_value_;
3779   double double_value_;
3780   ExternalReference external_reference_value_;
3781
3782   static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3783   InstanceType instance_type_;
3784 };
3785
3786
3787 class HBinaryOperation : public HTemplateInstruction<3> {
3788  public:
3789   HBinaryOperation(HValue* context, HValue* left, HValue* right,
3790                    HType type = HType::Tagged())
3791       : HTemplateInstruction<3>(type),
3792         observed_output_representation_(Representation::None()) {
3793     DCHECK(left != NULL && right != NULL);
3794     SetOperandAt(0, context);
3795     SetOperandAt(1, left);
3796     SetOperandAt(2, right);
3797     observed_input_representation_[0] = Representation::None();
3798     observed_input_representation_[1] = Representation::None();
3799   }
3800
3801   HValue* context() const { return OperandAt(0); }
3802   HValue* left() const { return OperandAt(1); }
3803   HValue* right() const { return OperandAt(2); }
3804
3805   // True if switching left and right operands likely generates better code.
3806   bool AreOperandsBetterSwitched() {
3807     if (!IsCommutative()) return false;
3808
3809     // Constant operands are better off on the right, they can be inlined in
3810     // many situations on most platforms.
3811     if (left()->IsConstant()) return true;
3812     if (right()->IsConstant()) return false;
3813
3814     // Otherwise, if there is only one use of the right operand, it would be
3815     // better off on the left for platforms that only have 2-arg arithmetic
3816     // ops (e.g ia32, x64) that clobber the left operand.
3817     return right()->HasOneUse();
3818   }
3819
3820   HValue* BetterLeftOperand() {
3821     return AreOperandsBetterSwitched() ? right() : left();
3822   }
3823
3824   HValue* BetterRightOperand() {
3825     return AreOperandsBetterSwitched() ? left() : right();
3826   }
3827
3828   void set_observed_input_representation(int index, Representation rep) {
3829     DCHECK(index >= 1 && index <= 2);
3830     observed_input_representation_[index - 1] = rep;
3831   }
3832
3833   virtual void initialize_output_representation(Representation observed) {
3834     observed_output_representation_ = observed;
3835   }
3836
3837   virtual Representation observed_input_representation(int index) V8_OVERRIDE {
3838     if (index == 0) return Representation::Tagged();
3839     return observed_input_representation_[index - 1];
3840   }
3841
3842   virtual void UpdateRepresentation(Representation new_rep,
3843                                     HInferRepresentationPhase* h_infer,
3844                                     const char* reason) V8_OVERRIDE {
3845     Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3846         ? Representation::Integer32() : new_rep;
3847     HValue::UpdateRepresentation(rep, h_infer, reason);
3848   }
3849
3850   virtual void InferRepresentation(
3851       HInferRepresentationPhase* h_infer) V8_OVERRIDE;
3852   virtual Representation RepresentationFromInputs() V8_OVERRIDE;
3853   Representation RepresentationFromOutput();
3854   virtual void AssumeRepresentation(Representation r) V8_OVERRIDE;
3855
3856   virtual bool IsCommutative() const { return false; }
3857
3858   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
3859
3860   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3861     if (index == 0) return Representation::Tagged();
3862     return representation();
3863   }
3864
3865   void SetOperandPositions(Zone* zone,
3866                            HSourcePosition left_pos,
3867                            HSourcePosition right_pos) {
3868     set_operand_position(zone, 1, left_pos);
3869     set_operand_position(zone, 2, right_pos);
3870   }
3871
3872   bool RightIsPowerOf2() {
3873     if (!right()->IsInteger32Constant()) return false;
3874     int32_t value = right()->GetInteger32Constant();
3875     return IsPowerOf2(value) || IsPowerOf2(-value);
3876   }
3877
3878   DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3879
3880  private:
3881   bool IgnoreObservedOutputRepresentation(Representation current_rep);
3882
3883   Representation observed_input_representation_[2];
3884   Representation observed_output_representation_;
3885 };
3886
3887
3888 class HWrapReceiver V8_FINAL : public HTemplateInstruction<2> {
3889  public:
3890   DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3891
3892   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3893
3894   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3895     return Representation::Tagged();
3896   }
3897
3898   HValue* receiver() const { return OperandAt(0); }
3899   HValue* function() const { return OperandAt(1); }
3900
3901   virtual HValue* Canonicalize() V8_OVERRIDE;
3902
3903   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
3904   bool known_function() const { return known_function_; }
3905
3906   DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3907
3908  private:
3909   HWrapReceiver(HValue* receiver, HValue* function) {
3910     known_function_ = function->IsConstant() &&
3911         HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3912     set_representation(Representation::Tagged());
3913     SetOperandAt(0, receiver);
3914     SetOperandAt(1, function);
3915     SetFlag(kUseGVN);
3916   }
3917
3918   bool known_function_;
3919 };
3920
3921
3922 class HApplyArguments V8_FINAL : public HTemplateInstruction<4> {
3923  public:
3924   DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3925                                  HValue*);
3926
3927   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3928     // The length is untagged, all other inputs are tagged.
3929     return (index == 2)
3930         ? Representation::Integer32()
3931         : Representation::Tagged();
3932   }
3933
3934   HValue* function() { return OperandAt(0); }
3935   HValue* receiver() { return OperandAt(1); }
3936   HValue* length() { return OperandAt(2); }
3937   HValue* elements() { return OperandAt(3); }
3938
3939   DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3940
3941  private:
3942   HApplyArguments(HValue* function,
3943                   HValue* receiver,
3944                   HValue* length,
3945                   HValue* elements) {
3946     set_representation(Representation::Tagged());
3947     SetOperandAt(0, function);
3948     SetOperandAt(1, receiver);
3949     SetOperandAt(2, length);
3950     SetOperandAt(3, elements);
3951     SetAllSideEffects();
3952   }
3953 };
3954
3955
3956 class HArgumentsElements V8_FINAL : public HTemplateInstruction<0> {
3957  public:
3958   DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3959
3960   DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3961
3962   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3963     return Representation::None();
3964   }
3965
3966   bool from_inlined() const { return from_inlined_; }
3967
3968  protected:
3969   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3970
3971  private:
3972   explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3973     // The value produced by this instruction is a pointer into the stack
3974     // that looks as if it was a smi because of alignment.
3975     set_representation(Representation::Tagged());
3976     SetFlag(kUseGVN);
3977   }
3978
3979   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
3980
3981   bool from_inlined_;
3982 };
3983
3984
3985 class HArgumentsLength V8_FINAL : public HUnaryOperation {
3986  public:
3987   DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3988
3989   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
3990     return Representation::Tagged();
3991   }
3992
3993   DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3994
3995  protected:
3996   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
3997
3998  private:
3999   explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
4000     set_representation(Representation::Integer32());
4001     SetFlag(kUseGVN);
4002   }
4003
4004   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4005 };
4006
4007
4008 class HAccessArgumentsAt V8_FINAL : public HTemplateInstruction<3> {
4009  public:
4010   DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
4011
4012   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4013
4014   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4015     // The arguments elements is considered tagged.
4016     return index == 0
4017         ? Representation::Tagged()
4018         : Representation::Integer32();
4019   }
4020
4021   HValue* arguments() const { return OperandAt(0); }
4022   HValue* length() const { return OperandAt(1); }
4023   HValue* index() const { return OperandAt(2); }
4024
4025   DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4026
4027  private:
4028   HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4029     set_representation(Representation::Tagged());
4030     SetFlag(kUseGVN);
4031     SetOperandAt(0, arguments);
4032     SetOperandAt(1, length);
4033     SetOperandAt(2, index);
4034   }
4035
4036   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4037 };
4038
4039
4040 class HBoundsCheckBaseIndexInformation;
4041
4042
4043 class HBoundsCheck V8_FINAL : public HTemplateInstruction<2> {
4044  public:
4045   DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4046
4047   bool skip_check() const { return skip_check_; }
4048   void set_skip_check() { skip_check_ = true; }
4049
4050   HValue* base() const { return base_; }
4051   int offset() const { return offset_; }
4052   int scale() const { return scale_; }
4053
4054   void ApplyIndexChange();
4055   bool DetectCompoundIndex() {
4056     DCHECK(base() == NULL);
4057
4058     DecompositionResult decomposition;
4059     if (index()->TryDecompose(&decomposition)) {
4060       base_ = decomposition.base();
4061       offset_ = decomposition.offset();
4062       scale_ = decomposition.scale();
4063       return true;
4064     } else {
4065       base_ = index();
4066       offset_ = 0;
4067       scale_ = 0;
4068       return false;
4069     }
4070   }
4071
4072   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4073     return representation();
4074   }
4075
4076   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4077   virtual void InferRepresentation(
4078       HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4079
4080   HValue* index() const { return OperandAt(0); }
4081   HValue* length() const { return OperandAt(1); }
4082   bool allow_equality() const { return allow_equality_; }
4083   void set_allow_equality(bool v) { allow_equality_ = v; }
4084
4085   virtual int RedefinedOperandIndex() V8_OVERRIDE { return 0; }
4086   virtual bool IsPurelyInformativeDefinition() V8_OVERRIDE {
4087     return skip_check();
4088   }
4089
4090   DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4091
4092  protected:
4093   friend class HBoundsCheckBaseIndexInformation;
4094
4095   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4096
4097   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4098   bool skip_check_;
4099   HValue* base_;
4100   int offset_;
4101   int scale_;
4102   bool allow_equality_;
4103
4104  private:
4105   // Normally HBoundsCheck should be created using the
4106   // HGraphBuilder::AddBoundsCheck() helper.
4107   // However when building stubs, where we know that the arguments are Int32,
4108   // it makes sense to invoke this constructor directly.
4109   HBoundsCheck(HValue* index, HValue* length)
4110     : skip_check_(false),
4111       base_(NULL), offset_(0), scale_(0),
4112       allow_equality_(false) {
4113     SetOperandAt(0, index);
4114     SetOperandAt(1, length);
4115     SetFlag(kFlexibleRepresentation);
4116     SetFlag(kUseGVN);
4117   }
4118
4119   virtual bool IsDeletable() const V8_OVERRIDE {
4120     return skip_check() && !FLAG_debug_code;
4121   }
4122 };
4123
4124
4125 class HBoundsCheckBaseIndexInformation V8_FINAL
4126     : public HTemplateInstruction<2> {
4127  public:
4128   explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4129     DecompositionResult decomposition;
4130     if (check->index()->TryDecompose(&decomposition)) {
4131       SetOperandAt(0, decomposition.base());
4132       SetOperandAt(1, check);
4133     } else {
4134       UNREACHABLE();
4135     }
4136   }
4137
4138   HValue* base_index() const { return OperandAt(0); }
4139   HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4140
4141   DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4142
4143   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4144     return representation();
4145   }
4146
4147   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4148
4149   virtual int RedefinedOperandIndex() V8_OVERRIDE { return 0; }
4150   virtual bool IsPurelyInformativeDefinition() V8_OVERRIDE { return true; }
4151 };
4152
4153
4154 class HBitwiseBinaryOperation : public HBinaryOperation {
4155  public:
4156   HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4157                           HType type = HType::TaggedNumber())
4158       : HBinaryOperation(context, left, right, type) {
4159     SetFlag(kFlexibleRepresentation);
4160     SetFlag(kTruncatingToInt32);
4161     SetFlag(kAllowUndefinedAsNaN);
4162     SetAllSideEffects();
4163   }
4164
4165   virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
4166     if (to.IsTagged() &&
4167         (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4168       SetAllSideEffects();
4169       ClearFlag(kUseGVN);
4170     } else {
4171       ClearAllSideEffects();
4172       SetFlag(kUseGVN);
4173     }
4174     if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4175   }
4176
4177   virtual void UpdateRepresentation(Representation new_rep,
4178                                     HInferRepresentationPhase* h_infer,
4179                                     const char* reason) V8_OVERRIDE {
4180     // We only generate either int32 or generic tagged bitwise operations.
4181     if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4182     HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4183   }
4184
4185   virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4186     Representation r = HBinaryOperation::observed_input_representation(index);
4187     if (r.IsDouble()) return Representation::Integer32();
4188     return r;
4189   }
4190
4191   virtual void initialize_output_representation(Representation observed) {
4192     if (observed.IsDouble()) observed = Representation::Integer32();
4193     HBinaryOperation::initialize_output_representation(observed);
4194   }
4195
4196   DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4197
4198  private:
4199   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4200 };
4201
4202
4203 class HMathFloorOfDiv V8_FINAL : public HBinaryOperation {
4204  public:
4205   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4206                                               HValue*,
4207                                               HValue*);
4208
4209   DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4210
4211  protected:
4212   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4213
4214  private:
4215   HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4216       : HBinaryOperation(context, left, right) {
4217     set_representation(Representation::Integer32());
4218     SetFlag(kUseGVN);
4219     SetFlag(kCanOverflow);
4220     SetFlag(kCanBeDivByZero);
4221     SetFlag(kLeftCanBeMinInt);
4222     SetFlag(kLeftCanBeNegative);
4223     SetFlag(kLeftCanBePositive);
4224     SetFlag(kAllowUndefinedAsNaN);
4225   }
4226
4227   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4228
4229   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4230 };
4231
4232
4233 class HArithmeticBinaryOperation : public HBinaryOperation {
4234  public:
4235   HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
4236       : HBinaryOperation(context, left, right, HType::TaggedNumber()) {
4237     SetAllSideEffects();
4238     SetFlag(kFlexibleRepresentation);
4239     SetFlag(kAllowUndefinedAsNaN);
4240   }
4241
4242   virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
4243     if (to.IsTagged() &&
4244         (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4245       SetAllSideEffects();
4246       ClearFlag(kUseGVN);
4247     } else {
4248       ClearAllSideEffects();
4249       SetFlag(kUseGVN);
4250     }
4251     if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4252   }
4253
4254   DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4255
4256  private:
4257   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4258 };
4259
4260
4261 class HCompareGeneric V8_FINAL : public HBinaryOperation {
4262  public:
4263   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HCompareGeneric, HValue*,
4264                                               HValue*, Token::Value);
4265
4266   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4267     return index == 0
4268         ? Representation::Tagged()
4269         : representation();
4270   }
4271
4272   Token::Value token() const { return token_; }
4273   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4274
4275   DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4276
4277  private:
4278   HCompareGeneric(HValue* context,
4279                   HValue* left,
4280                   HValue* right,
4281                   Token::Value token)
4282       : HBinaryOperation(context, left, right, HType::Boolean()),
4283         token_(token) {
4284     DCHECK(Token::IsCompareOp(token));
4285     set_representation(Representation::Tagged());
4286     SetAllSideEffects();
4287   }
4288
4289   Token::Value token_;
4290 };
4291
4292
4293 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4294  public:
4295   DECLARE_INSTRUCTION_FACTORY_P3(HCompareNumericAndBranch,
4296                                  HValue*, HValue*, Token::Value);
4297   DECLARE_INSTRUCTION_FACTORY_P5(HCompareNumericAndBranch,
4298                                  HValue*, HValue*, Token::Value,
4299                                  HBasicBlock*, HBasicBlock*);
4300
4301   HValue* left() const { return OperandAt(0); }
4302   HValue* right() const { return OperandAt(1); }
4303   Token::Value token() const { return token_; }
4304
4305   void set_observed_input_representation(Representation left,
4306                                          Representation right) {
4307       observed_input_representation_[0] = left;
4308       observed_input_representation_[1] = right;
4309   }
4310
4311   virtual void InferRepresentation(
4312       HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4313
4314   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4315     return representation();
4316   }
4317   virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4318     return observed_input_representation_[index];
4319   }
4320
4321   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4322
4323   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4324
4325   void SetOperandPositions(Zone* zone,
4326                            HSourcePosition left_pos,
4327                            HSourcePosition right_pos) {
4328     set_operand_position(zone, 0, left_pos);
4329     set_operand_position(zone, 1, right_pos);
4330   }
4331
4332   DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4333
4334  private:
4335   HCompareNumericAndBranch(HValue* left,
4336                            HValue* right,
4337                            Token::Value token,
4338                            HBasicBlock* true_target = NULL,
4339                            HBasicBlock* false_target = NULL)
4340       : token_(token) {
4341     SetFlag(kFlexibleRepresentation);
4342     DCHECK(Token::IsCompareOp(token));
4343     SetOperandAt(0, left);
4344     SetOperandAt(1, right);
4345     SetSuccessorAt(0, true_target);
4346     SetSuccessorAt(1, false_target);
4347   }
4348
4349   Representation observed_input_representation_[2];
4350   Token::Value token_;
4351 };
4352
4353
4354 class HCompareHoleAndBranch V8_FINAL : public HUnaryControlInstruction {
4355  public:
4356   DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4357   DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4358                                  HBasicBlock*, HBasicBlock*);
4359
4360   virtual void InferRepresentation(
4361       HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4362
4363   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4364     return representation();
4365   }
4366
4367   DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4368
4369  private:
4370   HCompareHoleAndBranch(HValue* value,
4371                         HBasicBlock* true_target = NULL,
4372                         HBasicBlock* false_target = NULL)
4373       : HUnaryControlInstruction(value, true_target, false_target) {
4374     SetFlag(kFlexibleRepresentation);
4375     SetFlag(kAllowUndefinedAsNaN);
4376   }
4377 };
4378
4379
4380 class HCompareMinusZeroAndBranch V8_FINAL : public HUnaryControlInstruction {
4381  public:
4382   DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4383
4384   virtual void InferRepresentation(
4385       HInferRepresentationPhase* h_infer) V8_OVERRIDE;
4386
4387   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4388     return representation();
4389   }
4390
4391   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4392
4393   DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4394
4395  private:
4396   explicit HCompareMinusZeroAndBranch(HValue* value)
4397       : HUnaryControlInstruction(value, NULL, NULL) {
4398   }
4399 };
4400
4401
4402 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4403  public:
4404   DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4405   DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4406                                  HBasicBlock*, HBasicBlock*);
4407
4408   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4409
4410   static const int kNoKnownSuccessorIndex = -1;
4411   int known_successor_index() const { return known_successor_index_; }
4412   void set_known_successor_index(int known_successor_index) {
4413     known_successor_index_ = known_successor_index;
4414   }
4415
4416   HValue* left() const { return OperandAt(0); }
4417   HValue* right() const { return OperandAt(1); }
4418
4419   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4420
4421   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4422     return Representation::Tagged();
4423   }
4424
4425   virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4426     return Representation::Tagged();
4427   }
4428
4429   DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4430
4431  private:
4432   HCompareObjectEqAndBranch(HValue* left,
4433                             HValue* right,
4434                             HBasicBlock* true_target = NULL,
4435                             HBasicBlock* false_target = NULL)
4436       : known_successor_index_(kNoKnownSuccessorIndex) {
4437     SetOperandAt(0, left);
4438     SetOperandAt(1, right);
4439     SetSuccessorAt(0, true_target);
4440     SetSuccessorAt(1, false_target);
4441   }
4442
4443   int known_successor_index_;
4444 };
4445
4446
4447 class HIsObjectAndBranch V8_FINAL : public HUnaryControlInstruction {
4448  public:
4449   DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
4450   DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
4451                                  HBasicBlock*, HBasicBlock*);
4452
4453   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4454     return Representation::Tagged();
4455   }
4456
4457   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4458
4459   DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
4460
4461  private:
4462   HIsObjectAndBranch(HValue* value,
4463                      HBasicBlock* true_target = NULL,
4464                      HBasicBlock* false_target = NULL)
4465     : HUnaryControlInstruction(value, true_target, false_target) {}
4466 };
4467
4468
4469 class HIsStringAndBranch V8_FINAL : public HUnaryControlInstruction {
4470  public:
4471   DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4472   DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4473                                  HBasicBlock*, HBasicBlock*);
4474
4475   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4476     return Representation::Tagged();
4477   }
4478
4479   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4480
4481   static const int kNoKnownSuccessorIndex = -1;
4482   int known_successor_index() const { return known_successor_index_; }
4483   void set_known_successor_index(int known_successor_index) {
4484     known_successor_index_ = known_successor_index;
4485   }
4486
4487   DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4488
4489  protected:
4490   virtual int RedefinedOperandIndex() { return 0; }
4491
4492  private:
4493   HIsStringAndBranch(HValue* value,
4494                      HBasicBlock* true_target = NULL,
4495                      HBasicBlock* false_target = NULL)
4496     : HUnaryControlInstruction(value, true_target, false_target),
4497       known_successor_index_(kNoKnownSuccessorIndex) { }
4498
4499   int known_successor_index_;
4500 };
4501
4502
4503 class HIsSmiAndBranch V8_FINAL : public HUnaryControlInstruction {
4504  public:
4505   DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4506   DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4507                                  HBasicBlock*, HBasicBlock*);
4508
4509   DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4510
4511   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4512     return Representation::Tagged();
4513   }
4514
4515  protected:
4516   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4517   virtual int RedefinedOperandIndex() { return 0; }
4518
4519  private:
4520   HIsSmiAndBranch(HValue* value,
4521                   HBasicBlock* true_target = NULL,
4522                   HBasicBlock* false_target = NULL)
4523       : HUnaryControlInstruction(value, true_target, false_target) {
4524     set_representation(Representation::Tagged());
4525   }
4526 };
4527
4528
4529 class HIsUndetectableAndBranch V8_FINAL : public HUnaryControlInstruction {
4530  public:
4531   DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4532   DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4533                                  HBasicBlock*, HBasicBlock*);
4534
4535   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4536     return Representation::Tagged();
4537   }
4538
4539   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4540
4541   DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4542
4543  private:
4544   HIsUndetectableAndBranch(HValue* value,
4545                            HBasicBlock* true_target = NULL,
4546                            HBasicBlock* false_target = NULL)
4547       : HUnaryControlInstruction(value, true_target, false_target) {}
4548 };
4549
4550
4551 class HStringCompareAndBranch : public HTemplateControlInstruction<2, 3> {
4552  public:
4553   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4554                                               HValue*,
4555                                               HValue*,
4556                                               Token::Value);
4557
4558   HValue* context() { return OperandAt(0); }
4559   HValue* left() { return OperandAt(1); }
4560   HValue* right() { return OperandAt(2); }
4561   Token::Value token() const { return token_; }
4562
4563   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4564
4565   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4566     return Representation::Tagged();
4567   }
4568
4569   Representation GetInputRepresentation() const {
4570     return Representation::Tagged();
4571   }
4572
4573   DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4574
4575  private:
4576   HStringCompareAndBranch(HValue* context,
4577                           HValue* left,
4578                           HValue* right,
4579                           Token::Value token)
4580       : token_(token) {
4581     DCHECK(Token::IsCompareOp(token));
4582     SetOperandAt(0, context);
4583     SetOperandAt(1, left);
4584     SetOperandAt(2, right);
4585     set_representation(Representation::Tagged());
4586     SetChangesFlag(kNewSpacePromotion);
4587   }
4588
4589   Token::Value token_;
4590 };
4591
4592
4593 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> {
4594  public:
4595   DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch);
4596
4597   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4598     return Representation::None();
4599   }
4600
4601   DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
4602  private:
4603   HIsConstructCallAndBranch() {}
4604 };
4605
4606
4607 class HHasInstanceTypeAndBranch V8_FINAL : public HUnaryControlInstruction {
4608  public:
4609   DECLARE_INSTRUCTION_FACTORY_P2(
4610       HHasInstanceTypeAndBranch, HValue*, InstanceType);
4611   DECLARE_INSTRUCTION_FACTORY_P3(
4612       HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4613
4614   InstanceType from() { return from_; }
4615   InstanceType to() { return to_; }
4616
4617   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4618
4619   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4620     return Representation::Tagged();
4621   }
4622
4623   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4624
4625   DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4626
4627  private:
4628   HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4629       : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
4630   HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4631       : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4632     DCHECK(to == LAST_TYPE);  // Others not implemented yet in backend.
4633   }
4634
4635   InstanceType from_;
4636   InstanceType to_;  // Inclusive range, not all combinations work.
4637 };
4638
4639
4640 class HHasCachedArrayIndexAndBranch V8_FINAL : public HUnaryControlInstruction {
4641  public:
4642   DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4643
4644   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4645     return Representation::Tagged();
4646   }
4647
4648   DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4649  private:
4650   explicit HHasCachedArrayIndexAndBranch(HValue* value)
4651       : HUnaryControlInstruction(value, NULL, NULL) { }
4652 };
4653
4654
4655 class HGetCachedArrayIndex V8_FINAL : public HUnaryOperation {
4656  public:
4657   DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4658
4659   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4660     return Representation::Tagged();
4661   }
4662
4663   DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4664
4665  protected:
4666   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4667
4668  private:
4669   explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4670     set_representation(Representation::Tagged());
4671     SetFlag(kUseGVN);
4672   }
4673
4674   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
4675 };
4676
4677
4678 class HClassOfTestAndBranch V8_FINAL : public HUnaryControlInstruction {
4679  public:
4680   DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4681                                  Handle<String>);
4682
4683   DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4684
4685   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4686     return Representation::Tagged();
4687   }
4688
4689   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4690
4691   Handle<String> class_name() const { return class_name_; }
4692
4693  private:
4694   HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4695       : HUnaryControlInstruction(value, NULL, NULL),
4696         class_name_(class_name) { }
4697
4698   Handle<String> class_name_;
4699 };
4700
4701
4702 class HTypeofIsAndBranch V8_FINAL : public HUnaryControlInstruction {
4703  public:
4704   DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4705
4706   Handle<String> type_literal() const { return type_literal_.handle(); }
4707   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4708
4709   DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4710
4711   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4712     return Representation::None();
4713   }
4714
4715   virtual bool KnownSuccessorBlock(HBasicBlock** block) V8_OVERRIDE;
4716
4717   virtual void FinalizeUniqueness() V8_OVERRIDE {
4718     type_literal_ = Unique<String>(type_literal_.handle());
4719   }
4720
4721  private:
4722   HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4723       : HUnaryControlInstruction(value, NULL, NULL),
4724         type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4725
4726   Unique<String> type_literal_;
4727 };
4728
4729
4730 class HInstanceOf V8_FINAL : public HBinaryOperation {
4731  public:
4732   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4733
4734   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4735     return Representation::Tagged();
4736   }
4737
4738   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
4739
4740   DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4741
4742  private:
4743   HInstanceOf(HValue* context, HValue* left, HValue* right)
4744       : HBinaryOperation(context, left, right, HType::Boolean()) {
4745     set_representation(Representation::Tagged());
4746     SetAllSideEffects();
4747   }
4748 };
4749
4750
4751 class HInstanceOfKnownGlobal V8_FINAL : public HTemplateInstruction<2> {
4752  public:
4753   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOfKnownGlobal,
4754                                               HValue*,
4755                                               Handle<JSFunction>);
4756
4757   HValue* context() { return OperandAt(0); }
4758   HValue* left() { return OperandAt(1); }
4759   Handle<JSFunction> function() { return function_; }
4760
4761   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4762     return Representation::Tagged();
4763   }
4764
4765   DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
4766
4767  private:
4768   HInstanceOfKnownGlobal(HValue* context,
4769                          HValue* left,
4770                          Handle<JSFunction> right)
4771       : HTemplateInstruction<2>(HType::Boolean()), function_(right) {
4772     SetOperandAt(0, context);
4773     SetOperandAt(1, left);
4774     set_representation(Representation::Tagged());
4775     SetAllSideEffects();
4776   }
4777
4778   Handle<JSFunction> function_;
4779 };
4780
4781
4782 class HPower V8_FINAL : public HTemplateInstruction<2> {
4783  public:
4784   static HInstruction* New(Zone* zone,
4785                            HValue* context,
4786                            HValue* left,
4787                            HValue* right);
4788
4789   HValue* left() { return OperandAt(0); }
4790   HValue* right() const { return OperandAt(1); }
4791
4792   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
4793     return index == 0
4794       ? Representation::Double()
4795       : Representation::None();
4796   }
4797   virtual Representation observed_input_representation(int index) V8_OVERRIDE {
4798     return RequiredInputRepresentation(index);
4799   }
4800
4801   DECLARE_CONCRETE_INSTRUCTION(Power)
4802
4803  protected:
4804   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4805
4806  private:
4807   HPower(HValue* left, HValue* right) {
4808     SetOperandAt(0, left);
4809     SetOperandAt(1, right);
4810     set_representation(Representation::Double());
4811     SetFlag(kUseGVN);
4812     SetChangesFlag(kNewSpacePromotion);
4813   }
4814
4815   virtual bool IsDeletable() const V8_OVERRIDE {
4816     return !right()->representation().IsTagged();
4817   }
4818 };
4819
4820
4821 class HAdd V8_FINAL : public HArithmeticBinaryOperation {
4822  public:
4823   static HInstruction* New(Zone* zone,
4824                            HValue* context,
4825                            HValue* left,
4826                            HValue* right);
4827
4828   // Add is only commutative if two integer values are added and not if two
4829   // tagged values are added (because it might be a String concatenation).
4830   // We also do not commute (pointer + offset).
4831   virtual bool IsCommutative() const V8_OVERRIDE {
4832     return !representation().IsTagged() && !representation().IsExternal();
4833   }
4834
4835   virtual HValue* Canonicalize() V8_OVERRIDE;
4836
4837   virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
4838     if (left()->IsInteger32Constant()) {
4839       decomposition->Apply(right(), left()->GetInteger32Constant());
4840       return true;
4841     } else if (right()->IsInteger32Constant()) {
4842       decomposition->Apply(left(), right()->GetInteger32Constant());
4843       return true;
4844     } else {
4845       return false;
4846     }
4847   }
4848
4849   virtual void RepresentationChanged(Representation to) V8_OVERRIDE {
4850     if (to.IsTagged() &&
4851         (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4852          left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4853       SetAllSideEffects();
4854       ClearFlag(kUseGVN);
4855     } else {
4856       ClearAllSideEffects();
4857       SetFlag(kUseGVN);
4858     }
4859     if (to.IsTagged()) {
4860       SetChangesFlag(kNewSpacePromotion);
4861       ClearFlag(kAllowUndefinedAsNaN);
4862     }
4863   }
4864
4865   virtual Representation RepresentationFromInputs() V8_OVERRIDE;
4866
4867   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE;
4868
4869   DECLARE_CONCRETE_INSTRUCTION(Add)
4870
4871  protected:
4872   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4873
4874   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4875
4876  private:
4877   HAdd(HValue* context, HValue* left, HValue* right)
4878       : HArithmeticBinaryOperation(context, left, right) {
4879     SetFlag(kCanOverflow);
4880   }
4881 };
4882
4883
4884 class HSub V8_FINAL : public HArithmeticBinaryOperation {
4885  public:
4886   static HInstruction* New(Zone* zone,
4887                            HValue* context,
4888                            HValue* left,
4889                            HValue* right);
4890
4891   virtual HValue* Canonicalize() V8_OVERRIDE;
4892
4893   virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
4894     if (right()->IsInteger32Constant()) {
4895       decomposition->Apply(left(), -right()->GetInteger32Constant());
4896       return true;
4897     } else {
4898       return false;
4899     }
4900   }
4901
4902   DECLARE_CONCRETE_INSTRUCTION(Sub)
4903
4904  protected:
4905   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4906
4907   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4908
4909  private:
4910   HSub(HValue* context, HValue* left, HValue* right)
4911       : HArithmeticBinaryOperation(context, left, right) {
4912     SetFlag(kCanOverflow);
4913   }
4914 };
4915
4916
4917 class HMul V8_FINAL : public HArithmeticBinaryOperation {
4918  public:
4919   static HInstruction* New(Zone* zone,
4920                            HValue* context,
4921                            HValue* left,
4922                            HValue* right);
4923
4924   static HInstruction* NewImul(Zone* zone,
4925                          HValue* context,
4926                          HValue* left,
4927                          HValue* right) {
4928     HInstruction* instr = HMul::New(zone, context, left, right);
4929     if (!instr->IsMul()) return instr;
4930     HMul* mul = HMul::cast(instr);
4931     // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4932     mul->AssumeRepresentation(Representation::Integer32());
4933     mul->ClearFlag(HValue::kCanOverflow);
4934     return mul;
4935   }
4936
4937   virtual HValue* Canonicalize() V8_OVERRIDE;
4938
4939   // Only commutative if it is certain that not two objects are multiplicated.
4940   virtual bool IsCommutative() const V8_OVERRIDE {
4941     return !representation().IsTagged();
4942   }
4943
4944   virtual void UpdateRepresentation(Representation new_rep,
4945                                     HInferRepresentationPhase* h_infer,
4946                                     const char* reason) V8_OVERRIDE {
4947     HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4948   }
4949
4950   bool MulMinusOne();
4951
4952   DECLARE_CONCRETE_INSTRUCTION(Mul)
4953
4954  protected:
4955   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4956
4957   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4958
4959  private:
4960   HMul(HValue* context, HValue* left, HValue* right)
4961       : HArithmeticBinaryOperation(context, left, right) {
4962     SetFlag(kCanOverflow);
4963   }
4964 };
4965
4966
4967 class HMod V8_FINAL : public HArithmeticBinaryOperation {
4968  public:
4969   static HInstruction* New(Zone* zone,
4970                            HValue* context,
4971                            HValue* left,
4972                            HValue* right);
4973
4974   virtual HValue* Canonicalize() V8_OVERRIDE;
4975
4976   virtual void UpdateRepresentation(Representation new_rep,
4977                                     HInferRepresentationPhase* h_infer,
4978                                     const char* reason) V8_OVERRIDE {
4979     if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4980     HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4981   }
4982
4983   DECLARE_CONCRETE_INSTRUCTION(Mod)
4984
4985  protected:
4986   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
4987
4988   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
4989
4990  private:
4991   HMod(HValue* context,
4992        HValue* left,
4993        HValue* right) : HArithmeticBinaryOperation(context, left, right) {
4994     SetFlag(kCanBeDivByZero);
4995     SetFlag(kCanOverflow);
4996     SetFlag(kLeftCanBeNegative);
4997   }
4998 };
4999
5000
5001 class HDiv V8_FINAL : public HArithmeticBinaryOperation {
5002  public:
5003   static HInstruction* New(Zone* zone,
5004                            HValue* context,
5005                            HValue* left,
5006                            HValue* right);
5007
5008   virtual HValue* Canonicalize() V8_OVERRIDE;
5009
5010   virtual void UpdateRepresentation(Representation new_rep,
5011                                     HInferRepresentationPhase* h_infer,
5012                                     const char* reason) V8_OVERRIDE {
5013     if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5014     HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5015   }
5016
5017   DECLARE_CONCRETE_INSTRUCTION(Div)
5018
5019  protected:
5020   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5021
5022   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5023
5024  private:
5025   HDiv(HValue* context, HValue* left, HValue* right)
5026       : HArithmeticBinaryOperation(context, left, right) {
5027     SetFlag(kCanBeDivByZero);
5028     SetFlag(kCanOverflow);
5029   }
5030 };
5031
5032
5033 class HMathMinMax V8_FINAL : public HArithmeticBinaryOperation {
5034  public:
5035   enum Operation { kMathMin, kMathMax };
5036
5037   static HInstruction* New(Zone* zone,
5038                            HValue* context,
5039                            HValue* left,
5040                            HValue* right,
5041                            Operation op);
5042
5043   virtual Representation observed_input_representation(int index) V8_OVERRIDE {
5044     return RequiredInputRepresentation(index);
5045   }
5046
5047   virtual void InferRepresentation(
5048       HInferRepresentationPhase* h_infer) V8_OVERRIDE;
5049
5050   virtual Representation RepresentationFromInputs() V8_OVERRIDE {
5051     Representation left_rep = left()->representation();
5052     Representation right_rep = right()->representation();
5053     Representation result = Representation::Smi();
5054     result = result.generalize(left_rep);
5055     result = result.generalize(right_rep);
5056     if (result.IsTagged()) return Representation::Double();
5057     return result;
5058   }
5059
5060   virtual bool IsCommutative() const V8_OVERRIDE { return true; }
5061
5062   Operation operation() { return operation_; }
5063
5064   DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5065
5066  protected:
5067   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5068     return other->IsMathMinMax() &&
5069         HMathMinMax::cast(other)->operation_ == operation_;
5070   }
5071
5072   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5073
5074  private:
5075   HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5076       : HArithmeticBinaryOperation(context, left, right),
5077         operation_(op) { }
5078
5079   Operation operation_;
5080 };
5081
5082
5083 class HBitwise V8_FINAL : public HBitwiseBinaryOperation {
5084  public:
5085   static HInstruction* New(Zone* zone,
5086                            HValue* context,
5087                            Token::Value op,
5088                            HValue* left,
5089                            HValue* right);
5090
5091   Token::Value op() const { return op_; }
5092
5093   virtual bool IsCommutative() const V8_OVERRIDE { return true; }
5094
5095   virtual HValue* Canonicalize() V8_OVERRIDE;
5096
5097   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
5098
5099   DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5100
5101  protected:
5102   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5103     return op() == HBitwise::cast(other)->op();
5104   }
5105
5106   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5107
5108  private:
5109   HBitwise(HValue* context,
5110            Token::Value op,
5111            HValue* left,
5112            HValue* right)
5113       : HBitwiseBinaryOperation(context, left, right),
5114         op_(op) {
5115     DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5116     // BIT_AND with a smi-range positive value will always unset the
5117     // entire sign-extension of the smi-sign.
5118     if (op == Token::BIT_AND &&
5119         ((left->IsConstant() &&
5120           left->representation().IsSmi() &&
5121           HConstant::cast(left)->Integer32Value() >= 0) ||
5122          (right->IsConstant() &&
5123           right->representation().IsSmi() &&
5124           HConstant::cast(right)->Integer32Value() >= 0))) {
5125       SetFlag(kTruncatingToSmi);
5126       SetFlag(kTruncatingToInt32);
5127     // BIT_OR with a smi-range negative value will always set the entire
5128     // sign-extension of the smi-sign.
5129     } else if (op == Token::BIT_OR &&
5130         ((left->IsConstant() &&
5131           left->representation().IsSmi() &&
5132           HConstant::cast(left)->Integer32Value() < 0) ||
5133          (right->IsConstant() &&
5134           right->representation().IsSmi() &&
5135           HConstant::cast(right)->Integer32Value() < 0))) {
5136       SetFlag(kTruncatingToSmi);
5137       SetFlag(kTruncatingToInt32);
5138     }
5139   }
5140
5141   Token::Value op_;
5142 };
5143
5144
5145 class HShl V8_FINAL : public HBitwiseBinaryOperation {
5146  public:
5147   static HInstruction* New(Zone* zone,
5148                            HValue* context,
5149                            HValue* left,
5150                            HValue* right);
5151
5152   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5153
5154   virtual void UpdateRepresentation(Representation new_rep,
5155                                     HInferRepresentationPhase* h_infer,
5156                                     const char* reason) V8_OVERRIDE {
5157     if (new_rep.IsSmi() &&
5158         !(right()->IsInteger32Constant() &&
5159           right()->GetInteger32Constant() >= 0)) {
5160       new_rep = Representation::Integer32();
5161     }
5162     HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5163   }
5164
5165   DECLARE_CONCRETE_INSTRUCTION(Shl)
5166
5167  protected:
5168   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5169
5170  private:
5171   HShl(HValue* context, HValue* left, HValue* right)
5172       : HBitwiseBinaryOperation(context, left, right) { }
5173 };
5174
5175
5176 class HShr V8_FINAL : public HBitwiseBinaryOperation {
5177  public:
5178   static HInstruction* New(Zone* zone,
5179                            HValue* context,
5180                            HValue* left,
5181                            HValue* right);
5182
5183   virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
5184     if (right()->IsInteger32Constant()) {
5185       if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5186         // This is intended to look for HAdd and HSub, to handle compounds
5187         // like ((base + offset) >> scale) with one single decomposition.
5188         left()->TryDecompose(decomposition);
5189         return true;
5190       }
5191     }
5192     return false;
5193   }
5194
5195   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5196
5197   virtual void UpdateRepresentation(Representation new_rep,
5198                                     HInferRepresentationPhase* h_infer,
5199                                     const char* reason) V8_OVERRIDE {
5200     if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5201     HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5202   }
5203
5204   DECLARE_CONCRETE_INSTRUCTION(Shr)
5205
5206  protected:
5207   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5208
5209  private:
5210   HShr(HValue* context, HValue* left, HValue* right)
5211       : HBitwiseBinaryOperation(context, left, right) { }
5212 };
5213
5214
5215 class HSar V8_FINAL : public HBitwiseBinaryOperation {
5216  public:
5217   static HInstruction* New(Zone* zone,
5218                            HValue* context,
5219                            HValue* left,
5220                            HValue* right);
5221
5222   virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
5223     if (right()->IsInteger32Constant()) {
5224       if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5225         // This is intended to look for HAdd and HSub, to handle compounds
5226         // like ((base + offset) >> scale) with one single decomposition.
5227         left()->TryDecompose(decomposition);
5228         return true;
5229       }
5230     }
5231     return false;
5232   }
5233
5234   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
5235
5236   virtual void UpdateRepresentation(Representation new_rep,
5237                                     HInferRepresentationPhase* h_infer,
5238                                     const char* reason) V8_OVERRIDE {
5239     if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5240     HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5241   }
5242
5243   DECLARE_CONCRETE_INSTRUCTION(Sar)
5244
5245  protected:
5246   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5247
5248  private:
5249   HSar(HValue* context, HValue* left, HValue* right)
5250       : HBitwiseBinaryOperation(context, left, right) { }
5251 };
5252
5253
5254 class HRor V8_FINAL : public HBitwiseBinaryOperation {
5255  public:
5256   static HInstruction* New(Zone* zone,
5257                            HValue* context,
5258                            HValue* left,
5259                            HValue* right) {
5260     return new(zone) HRor(context, left, right);
5261   }
5262
5263   virtual void UpdateRepresentation(Representation new_rep,
5264                                     HInferRepresentationPhase* h_infer,
5265                                     const char* reason) V8_OVERRIDE {
5266     if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5267     HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5268   }
5269
5270   DECLARE_CONCRETE_INSTRUCTION(Ror)
5271
5272  protected:
5273   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
5274
5275  private:
5276   HRor(HValue* context, HValue* left, HValue* right)
5277        : HBitwiseBinaryOperation(context, left, right) {
5278     ChangeRepresentation(Representation::Integer32());
5279   }
5280 };
5281
5282
5283 class HOsrEntry V8_FINAL : public HTemplateInstruction<0> {
5284  public:
5285   DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5286
5287   BailoutId ast_id() const { return ast_id_; }
5288
5289   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5290     return Representation::None();
5291   }
5292
5293   DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5294
5295  private:
5296   explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5297     SetChangesFlag(kOsrEntries);
5298     SetChangesFlag(kNewSpacePromotion);
5299   }
5300
5301   BailoutId ast_id_;
5302 };
5303
5304
5305 class HParameter V8_FINAL : public HTemplateInstruction<0> {
5306  public:
5307   enum ParameterKind {
5308     STACK_PARAMETER,
5309     REGISTER_PARAMETER
5310   };
5311
5312   DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5313   DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5314   DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5315                                  Representation);
5316
5317   unsigned index() const { return index_; }
5318   ParameterKind kind() const { return kind_; }
5319
5320   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
5321
5322   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5323     return Representation::None();
5324   }
5325
5326   DECLARE_CONCRETE_INSTRUCTION(Parameter)
5327
5328  private:
5329   explicit HParameter(unsigned index,
5330                       ParameterKind kind = STACK_PARAMETER)
5331       : index_(index),
5332         kind_(kind) {
5333     set_representation(Representation::Tagged());
5334   }
5335
5336   explicit HParameter(unsigned index,
5337                       ParameterKind kind,
5338                       Representation r)
5339       : index_(index),
5340         kind_(kind) {
5341     set_representation(r);
5342   }
5343
5344   unsigned index_;
5345   ParameterKind kind_;
5346 };
5347
5348
5349 class HCallStub V8_FINAL : public HUnaryCall {
5350  public:
5351   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
5352   CodeStub::Major major_key() { return major_key_; }
5353
5354   HValue* context() { return value(); }
5355
5356   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
5357
5358   DECLARE_CONCRETE_INSTRUCTION(CallStub)
5359
5360  private:
5361   HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5362       : HUnaryCall(context, argument_count),
5363         major_key_(major_key) {
5364   }
5365
5366   CodeStub::Major major_key_;
5367 };
5368
5369
5370 class HUnknownOSRValue V8_FINAL : public HTemplateInstruction<0> {
5371  public:
5372   DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5373
5374   virtual OStream& PrintDataTo(OStream& os) const;  // NOLINT
5375
5376   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5377     return Representation::None();
5378   }
5379
5380   void set_incoming_value(HPhi* value) { incoming_value_ = value; }
5381   HPhi* incoming_value() { return incoming_value_; }
5382   HEnvironment *environment() { return environment_; }
5383   int index() { return index_; }
5384
5385   virtual Representation KnownOptimalRepresentation() V8_OVERRIDE {
5386     if (incoming_value_ == NULL) return Representation::None();
5387     return incoming_value_->KnownOptimalRepresentation();
5388   }
5389
5390   DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5391
5392  private:
5393   HUnknownOSRValue(HEnvironment* environment, int index)
5394       : environment_(environment),
5395         index_(index),
5396         incoming_value_(NULL) {
5397     set_representation(Representation::Tagged());
5398   }
5399
5400   HEnvironment* environment_;
5401   int index_;
5402   HPhi* incoming_value_;
5403 };
5404
5405
5406 class HLoadGlobalCell V8_FINAL : public HTemplateInstruction<0> {
5407  public:
5408   DECLARE_INSTRUCTION_FACTORY_P2(HLoadGlobalCell, Handle<Cell>,
5409                                  PropertyDetails);
5410
5411   Unique<Cell> cell() const { return cell_; }
5412   bool RequiresHoleCheck() const;
5413
5414   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
5415
5416   virtual intptr_t Hashcode() V8_OVERRIDE {
5417     return cell_.Hashcode();
5418   }
5419
5420   virtual void FinalizeUniqueness() V8_OVERRIDE {
5421     cell_ = Unique<Cell>(cell_.handle());
5422   }
5423
5424   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5425     return Representation::None();
5426   }
5427
5428   DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell)
5429
5430  protected:
5431   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5432     return cell_ == HLoadGlobalCell::cast(other)->cell_;
5433   }
5434
5435  private:
5436   HLoadGlobalCell(Handle<Cell> cell, PropertyDetails details)
5437     : cell_(Unique<Cell>::CreateUninitialized(cell)), details_(details) {
5438     set_representation(Representation::Tagged());
5439     SetFlag(kUseGVN);
5440     SetDependsOnFlag(kGlobalVars);
5441   }
5442
5443   virtual bool IsDeletable() const V8_OVERRIDE { return !RequiresHoleCheck(); }
5444
5445   Unique<Cell> cell_;
5446   PropertyDetails details_;
5447 };
5448
5449
5450 class HLoadGlobalGeneric V8_FINAL : public HTemplateInstruction<2> {
5451  public:
5452   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5453                                               Handle<String>, bool);
5454
5455   HValue* context() { return OperandAt(0); }
5456   HValue* global_object() { return OperandAt(1); }
5457   Handle<String> name() const { return name_; }
5458   bool for_typeof() const { return for_typeof_; }
5459   int slot() const {
5460     DCHECK(FLAG_vector_ics &&
5461            slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
5462     return slot_;
5463   }
5464   Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
5465   void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
5466     DCHECK(FLAG_vector_ics);
5467     feedback_vector_ = vector;
5468     slot_ = slot;
5469   }
5470
5471   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
5472
5473   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5474     return Representation::Tagged();
5475   }
5476
5477   DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5478
5479  private:
5480   HLoadGlobalGeneric(HValue* context, HValue* global_object,
5481                      Handle<String> name, bool for_typeof)
5482       : name_(name), for_typeof_(for_typeof),
5483         slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
5484     SetOperandAt(0, context);
5485     SetOperandAt(1, global_object);
5486     set_representation(Representation::Tagged());
5487     SetAllSideEffects();
5488   }
5489
5490   Handle<String> name_;
5491   bool for_typeof_;
5492   Handle<FixedArray> feedback_vector_;
5493   int slot_;
5494 };
5495
5496
5497 class HAllocate V8_FINAL : public HTemplateInstruction<2> {
5498  public:
5499   static bool CompatibleInstanceTypes(InstanceType type1,
5500                                       InstanceType type2) {
5501     return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5502         ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5503   }
5504
5505   static HAllocate* New(Zone* zone,
5506                         HValue* context,
5507                         HValue* size,
5508                         HType type,
5509                         PretenureFlag pretenure_flag,
5510                         InstanceType instance_type,
5511                         Handle<AllocationSite> allocation_site =
5512                             Handle<AllocationSite>::null()) {
5513     return new(zone) HAllocate(context, size, type, pretenure_flag,
5514         instance_type, allocation_site);
5515   }
5516
5517   // Maximum instance size for which allocations will be inlined.
5518   static const int kMaxInlineSize = 64 * kPointerSize;
5519
5520   HValue* context() const { return OperandAt(0); }
5521   HValue* size() const { return OperandAt(1); }
5522
5523   bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
5524   HConstant* size_upper_bound() { return size_upper_bound_; }
5525   void set_size_upper_bound(HConstant* value) {
5526     DCHECK(size_upper_bound_ == NULL);
5527     size_upper_bound_ = value;
5528   }
5529
5530   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5531     if (index == 0) {
5532       return Representation::Tagged();
5533     } else {
5534       return Representation::Integer32();
5535     }
5536   }
5537
5538   virtual Handle<Map> GetMonomorphicJSObjectMap() {
5539     return known_initial_map_;
5540   }
5541
5542   void set_known_initial_map(Handle<Map> known_initial_map) {
5543     known_initial_map_ = known_initial_map;
5544   }
5545
5546   bool IsNewSpaceAllocation() const {
5547     return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5548   }
5549
5550   bool IsOldDataSpaceAllocation() const {
5551     return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0;
5552   }
5553
5554   bool IsOldPointerSpaceAllocation() const {
5555     return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
5556   }
5557
5558   bool MustAllocateDoubleAligned() const {
5559     return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5560   }
5561
5562   bool MustPrefillWithFiller() const {
5563     return (flags_ & PREFILL_WITH_FILLER) != 0;
5564   }
5565
5566   void MakePrefillWithFiller() {
5567     flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5568   }
5569
5570   bool MustClearNextMapWord() const {
5571     return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5572   }
5573
5574   void MakeDoubleAligned() {
5575     flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5576   }
5577
5578   virtual bool HandleSideEffectDominator(GVNFlag side_effect,
5579                                          HValue* dominator) V8_OVERRIDE;
5580
5581   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
5582
5583   DECLARE_CONCRETE_INSTRUCTION(Allocate)
5584
5585  private:
5586   enum Flags {
5587     ALLOCATE_IN_NEW_SPACE = 1 << 0,
5588     ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
5589     ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
5590     ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5591     PREFILL_WITH_FILLER = 1 << 4,
5592     CLEAR_NEXT_MAP_WORD = 1 << 5
5593   };
5594
5595   HAllocate(HValue* context,
5596             HValue* size,
5597             HType type,
5598             PretenureFlag pretenure_flag,
5599             InstanceType instance_type,
5600             Handle<AllocationSite> allocation_site =
5601                 Handle<AllocationSite>::null())
5602       : HTemplateInstruction<2>(type),
5603         flags_(ComputeFlags(pretenure_flag, instance_type)),
5604         dominating_allocate_(NULL),
5605         filler_free_space_size_(NULL),
5606         size_upper_bound_(NULL) {
5607     SetOperandAt(0, context);
5608     UpdateSize(size);
5609     set_representation(Representation::Tagged());
5610     SetFlag(kTrackSideEffectDominators);
5611     SetChangesFlag(kNewSpacePromotion);
5612     SetDependsOnFlag(kNewSpacePromotion);
5613
5614     if (FLAG_trace_pretenuring) {
5615       PrintF("HAllocate with AllocationSite %p %s\n",
5616              allocation_site.is_null()
5617                  ? static_cast<void*>(NULL)
5618                  : static_cast<void*>(*allocation_site),
5619              pretenure_flag == TENURED ? "tenured" : "not tenured");
5620     }
5621   }
5622
5623   static Flags ComputeFlags(PretenureFlag pretenure_flag,
5624                             InstanceType instance_type) {
5625     Flags flags = pretenure_flag == TENURED
5626         ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE
5627             ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE)
5628         : ALLOCATE_IN_NEW_SPACE;
5629     if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5630       flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5631     }
5632     // We have to fill the allocated object with one word fillers if we do
5633     // not use allocation folding since some allocations may depend on each
5634     // other, i.e., have a pointer to each other. A GC in between these
5635     // allocations may leave such objects behind in a not completely initialized
5636     // state.
5637     if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5638       flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5639     }
5640     if (pretenure_flag == NOT_TENURED &&
5641         AllocationSite::CanTrack(instance_type)) {
5642       flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5643     }
5644     return flags;
5645   }
5646
5647   void UpdateClearNextMapWord(bool clear_next_map_word) {
5648     flags_ = static_cast<Flags>(clear_next_map_word
5649                                 ? flags_ | CLEAR_NEXT_MAP_WORD
5650                                 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5651   }
5652
5653   void UpdateSize(HValue* size) {
5654     SetOperandAt(1, size);
5655     if (size->IsInteger32Constant()) {
5656       size_upper_bound_ = HConstant::cast(size);
5657     } else {
5658       size_upper_bound_ = NULL;
5659     }
5660   }
5661
5662   HAllocate* GetFoldableDominator(HAllocate* dominator);
5663
5664   void UpdateFreeSpaceFiller(int32_t filler_size);
5665
5666   void CreateFreeSpaceFiller(int32_t filler_size);
5667
5668   bool IsFoldable(HAllocate* allocate) {
5669     return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5670         (IsOldDataSpaceAllocation() && allocate->IsOldDataSpaceAllocation()) ||
5671         (IsOldPointerSpaceAllocation() &&
5672             allocate->IsOldPointerSpaceAllocation());
5673   }
5674
5675   void ClearNextMapWord(int offset);
5676
5677   Flags flags_;
5678   Handle<Map> known_initial_map_;
5679   HAllocate* dominating_allocate_;
5680   HStoreNamedField* filler_free_space_size_;
5681   HConstant* size_upper_bound_;
5682 };
5683
5684
5685 class HStoreCodeEntry V8_FINAL: public HTemplateInstruction<2> {
5686  public:
5687   static HStoreCodeEntry* New(Zone* zone,
5688                               HValue* context,
5689                               HValue* function,
5690                               HValue* code) {
5691     return new(zone) HStoreCodeEntry(function, code);
5692   }
5693
5694   virtual Representation RequiredInputRepresentation(int index) {
5695     return Representation::Tagged();
5696   }
5697
5698   HValue* function() { return OperandAt(0); }
5699   HValue* code_object() { return OperandAt(1); }
5700
5701   DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5702
5703  private:
5704   HStoreCodeEntry(HValue* function, HValue* code) {
5705     SetOperandAt(0, function);
5706     SetOperandAt(1, code);
5707   }
5708 };
5709
5710
5711 class HInnerAllocatedObject V8_FINAL : public HTemplateInstruction<2> {
5712  public:
5713   static HInnerAllocatedObject* New(Zone* zone,
5714                                     HValue* context,
5715                                     HValue* value,
5716                                     HValue* offset,
5717                                     HType type) {
5718     return new(zone) HInnerAllocatedObject(value, offset, type);
5719   }
5720
5721   HValue* base_object() const { return OperandAt(0); }
5722   HValue* offset() const { return OperandAt(1); }
5723
5724   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5725     return index == 0 ? Representation::Tagged() : Representation::Integer32();
5726   }
5727
5728   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
5729
5730   DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5731
5732  private:
5733   HInnerAllocatedObject(HValue* value,
5734                         HValue* offset,
5735                         HType type) : HTemplateInstruction<2>(type) {
5736     DCHECK(value->IsAllocate());
5737     DCHECK(type.IsHeapObject());
5738     SetOperandAt(0, value);
5739     SetOperandAt(1, offset);
5740     set_representation(Representation::Tagged());
5741   }
5742 };
5743
5744
5745 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5746   return !value->type().IsSmi()
5747       && !value->type().IsNull()
5748       && !value->type().IsBoolean()
5749       && !value->type().IsUndefined()
5750       && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5751 }
5752
5753
5754 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5755                                             HValue* value,
5756                                             HValue* dominator) {
5757   while (object->IsInnerAllocatedObject()) {
5758     object = HInnerAllocatedObject::cast(object)->base_object();
5759   }
5760   if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
5761     return false;
5762   }
5763   if (object->IsConstant() &&
5764       HConstant::cast(object)->HasExternalReferenceValue()) {
5765     // Stores to external references require no write barriers
5766     return false;
5767   }
5768   // We definitely need a write barrier unless the object is the allocation
5769   // dominator.
5770   if (object == dominator && object->IsAllocate()) {
5771     // Stores to new space allocations require no write barriers.
5772     if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5773       return false;
5774     }
5775     // Stores to old space allocations require no write barriers if the value is
5776     // a constant provably not in new space.
5777     if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5778       return false;
5779     }
5780     // Stores to old space allocations require no write barriers if the value is
5781     // an old space allocation.
5782     while (value->IsInnerAllocatedObject()) {
5783       value = HInnerAllocatedObject::cast(value)->base_object();
5784     }
5785     if (value->IsAllocate() &&
5786         !HAllocate::cast(value)->IsNewSpaceAllocation()) {
5787       return false;
5788     }
5789   }
5790   return true;
5791 }
5792
5793
5794 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5795                                                         HValue* dominator) {
5796   while (object->IsInnerAllocatedObject()) {
5797     object = HInnerAllocatedObject::cast(object)->base_object();
5798   }
5799   if (object == dominator &&
5800       object->IsAllocate() &&
5801       HAllocate::cast(object)->IsNewSpaceAllocation()) {
5802     return kPointersToHereAreAlwaysInteresting;
5803   }
5804   return kPointersToHereMaybeInteresting;
5805 }
5806
5807
5808 class HStoreGlobalCell V8_FINAL : public HUnaryOperation {
5809  public:
5810   DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*,
5811                                  Handle<PropertyCell>, PropertyDetails);
5812
5813   Unique<PropertyCell> cell() const { return cell_; }
5814   bool RequiresHoleCheck() {
5815     return !details_.IsDontDelete() || details_.IsReadOnly();
5816   }
5817   bool NeedsWriteBarrier() {
5818     return StoringValueNeedsWriteBarrier(value());
5819   }
5820
5821   virtual void FinalizeUniqueness() V8_OVERRIDE {
5822     cell_ = Unique<PropertyCell>(cell_.handle());
5823   }
5824
5825   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5826     return Representation::Tagged();
5827   }
5828   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
5829
5830   DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
5831
5832  private:
5833   HStoreGlobalCell(HValue* value,
5834                    Handle<PropertyCell> cell,
5835                    PropertyDetails details)
5836       : HUnaryOperation(value),
5837         cell_(Unique<PropertyCell>::CreateUninitialized(cell)),
5838         details_(details) {
5839     SetChangesFlag(kGlobalVars);
5840   }
5841
5842   Unique<PropertyCell> cell_;
5843   PropertyDetails details_;
5844 };
5845
5846
5847 class HLoadContextSlot V8_FINAL : public HUnaryOperation {
5848  public:
5849   enum Mode {
5850     // Perform a normal load of the context slot without checking its value.
5851     kNoCheck,
5852     // Load and check the value of the context slot. Deoptimize if it's the
5853     // hole value. This is used for checking for loading of uninitialized
5854     // harmony bindings where we deoptimize into full-codegen generated code
5855     // which will subsequently throw a reference error.
5856     kCheckDeoptimize,
5857     // Load and check the value of the context slot. Return undefined if it's
5858     // the hole value. This is used for non-harmony const assignments
5859     kCheckReturnUndefined
5860   };
5861
5862   HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5863       : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5864     set_representation(Representation::Tagged());
5865     SetFlag(kUseGVN);
5866     SetDependsOnFlag(kContextSlots);
5867   }
5868
5869   int slot_index() const { return slot_index_; }
5870   Mode mode() const { return mode_; }
5871
5872   bool DeoptimizesOnHole() {
5873     return mode_ == kCheckDeoptimize;
5874   }
5875
5876   bool RequiresHoleCheck() const {
5877     return mode_ != kNoCheck;
5878   }
5879
5880   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5881     return Representation::Tagged();
5882   }
5883
5884   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
5885
5886   DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5887
5888  protected:
5889   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
5890     HLoadContextSlot* b = HLoadContextSlot::cast(other);
5891     return (slot_index() == b->slot_index());
5892   }
5893
5894  private:
5895   virtual bool IsDeletable() const V8_OVERRIDE { return !RequiresHoleCheck(); }
5896
5897   int slot_index_;
5898   Mode mode_;
5899 };
5900
5901
5902 class HStoreContextSlot V8_FINAL : public HTemplateInstruction<2> {
5903  public:
5904   enum Mode {
5905     // Perform a normal store to the context slot without checking its previous
5906     // value.
5907     kNoCheck,
5908     // Check the previous value of the context slot and deoptimize if it's the
5909     // hole value. This is used for checking for assignments to uninitialized
5910     // harmony bindings where we deoptimize into full-codegen generated code
5911     // which will subsequently throw a reference error.
5912     kCheckDeoptimize,
5913     // Check the previous value and ignore assignment if it isn't a hole value
5914     kCheckIgnoreAssignment
5915   };
5916
5917   DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5918                                  Mode, HValue*);
5919
5920   HValue* context() const { return OperandAt(0); }
5921   HValue* value() const { return OperandAt(1); }
5922   int slot_index() const { return slot_index_; }
5923   Mode mode() const { return mode_; }
5924
5925   bool NeedsWriteBarrier() {
5926     return StoringValueNeedsWriteBarrier(value());
5927   }
5928
5929   bool DeoptimizesOnHole() {
5930     return mode_ == kCheckDeoptimize;
5931   }
5932
5933   bool RequiresHoleCheck() {
5934     return mode_ != kNoCheck;
5935   }
5936
5937   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
5938     return Representation::Tagged();
5939   }
5940
5941   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
5942
5943   DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5944
5945  private:
5946   HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5947       : slot_index_(slot_index), mode_(mode) {
5948     SetOperandAt(0, context);
5949     SetOperandAt(1, value);
5950     SetChangesFlag(kContextSlots);
5951   }
5952
5953   int slot_index_;
5954   Mode mode_;
5955 };
5956
5957
5958 // Represents an access to a portion of an object, such as the map pointer,
5959 // array elements pointer, etc, but not accesses to array elements themselves.
5960 class HObjectAccess V8_FINAL {
5961  public:
5962   inline bool IsInobject() const {
5963     return portion() != kBackingStore && portion() != kExternalMemory;
5964   }
5965
5966   inline bool IsExternalMemory() const {
5967     return portion() == kExternalMemory;
5968   }
5969
5970   inline bool IsStringLength() const {
5971     return portion() == kStringLengths;
5972   }
5973
5974   inline bool IsMap() const {
5975     return portion() == kMaps;
5976   }
5977
5978   inline int offset() const {
5979     return OffsetField::decode(value_);
5980   }
5981
5982   inline Representation representation() const {
5983     return Representation::FromKind(RepresentationField::decode(value_));
5984   }
5985
5986   inline Handle<String> name() const {
5987     return name_;
5988   }
5989
5990   inline bool immutable() const {
5991     return ImmutableField::decode(value_);
5992   }
5993
5994   // Returns true if access is being made to an in-object property that
5995   // was already added to the object.
5996   inline bool existing_inobject_property() const {
5997     return ExistingInobjectPropertyField::decode(value_);
5998   }
5999
6000   inline HObjectAccess WithRepresentation(Representation representation) {
6001     return HObjectAccess(portion(), offset(), representation, name(),
6002                          immutable(), existing_inobject_property());
6003   }
6004
6005   static HObjectAccess ForHeapNumberValue() {
6006     return HObjectAccess(
6007         kDouble, HeapNumber::kValueOffset, Representation::Double());
6008   }
6009
6010   static HObjectAccess ForHeapNumberValueLowestBits() {
6011     return HObjectAccess(kDouble,
6012                          HeapNumber::kValueOffset,
6013                          Representation::Integer32());
6014   }
6015
6016   static HObjectAccess ForHeapNumberValueHighestBits() {
6017     return HObjectAccess(kDouble,
6018                          HeapNumber::kValueOffset + kIntSize,
6019                          Representation::Integer32());
6020   }
6021
6022   static HObjectAccess ForSIMD128Double0() {
6023     return HObjectAccess(
6024         kDouble, Float32x4::kValueOffset, Representation::Double());
6025   }
6026
6027   static HObjectAccess ForSIMD128Double1() {
6028     return HObjectAccess(kDouble,
6029                          Float32x4::kValueOffset + kDoubleSize,
6030                          Representation::Double());
6031   }
6032
6033   static HObjectAccess ForElementsPointer() {
6034     return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
6035   }
6036
6037   static HObjectAccess ForLiteralsPointer() {
6038     return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
6039   }
6040
6041   static HObjectAccess ForNextFunctionLinkPointer() {
6042     return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
6043   }
6044
6045   static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
6046     return HObjectAccess(
6047         kArrayLengths,
6048         JSArray::kLengthOffset,
6049         IsFastElementsKind(elements_kind)
6050             ? Representation::Smi() : Representation::Tagged());
6051   }
6052
6053   static HObjectAccess ForAllocationSiteOffset(int offset);
6054
6055   static HObjectAccess ForAllocationSiteList() {
6056     return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
6057                          Handle<String>::null(), false, false);
6058   }
6059
6060   static HObjectAccess ForFixedArrayLength() {
6061     return HObjectAccess(
6062         kArrayLengths,
6063         FixedArray::kLengthOffset,
6064         Representation::Smi());
6065   }
6066
6067   static HObjectAccess ForStringHashField() {
6068     return HObjectAccess(kInobject,
6069                          String::kHashFieldOffset,
6070                          Representation::Integer32());
6071   }
6072
6073   static HObjectAccess ForStringLength() {
6074     STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
6075     return HObjectAccess(
6076         kStringLengths,
6077         String::kLengthOffset,
6078         Representation::Smi());
6079   }
6080
6081   static HObjectAccess ForConsStringFirst() {
6082     return HObjectAccess(kInobject, ConsString::kFirstOffset);
6083   }
6084
6085   static HObjectAccess ForConsStringSecond() {
6086     return HObjectAccess(kInobject, ConsString::kSecondOffset);
6087   }
6088
6089   static HObjectAccess ForPropertiesPointer() {
6090     return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
6091   }
6092
6093   static HObjectAccess ForPrototypeOrInitialMap() {
6094     return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
6095   }
6096
6097   static HObjectAccess ForSharedFunctionInfoPointer() {
6098     return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
6099   }
6100
6101   static HObjectAccess ForCodeEntryPointer() {
6102     return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
6103   }
6104
6105   static HObjectAccess ForCodeOffset() {
6106     return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
6107   }
6108
6109   static HObjectAccess ForOptimizedCodeMap() {
6110     return HObjectAccess(kInobject,
6111                          SharedFunctionInfo::kOptimizedCodeMapOffset);
6112   }
6113
6114   static HObjectAccess ForFunctionContextPointer() {
6115     return HObjectAccess(kInobject, JSFunction::kContextOffset);
6116   }
6117
6118   static HObjectAccess ForMap() {
6119     return HObjectAccess(kMaps, JSObject::kMapOffset);
6120   }
6121
6122   static HObjectAccess ForMapAsInteger32() {
6123     return HObjectAccess(kMaps, JSObject::kMapOffset,
6124                          Representation::Integer32());
6125   }
6126
6127   static HObjectAccess ForMapInObjectProperties() {
6128     return HObjectAccess(kInobject,
6129                          Map::kInObjectPropertiesOffset,
6130                          Representation::UInteger8());
6131   }
6132
6133   static HObjectAccess ForMapInstanceType() {
6134     return HObjectAccess(kInobject,
6135                          Map::kInstanceTypeOffset,
6136                          Representation::UInteger8());
6137   }
6138
6139   static HObjectAccess ForMapInstanceSize() {
6140     return HObjectAccess(kInobject,
6141                          Map::kInstanceSizeOffset,
6142                          Representation::UInteger8());
6143   }
6144
6145   static HObjectAccess ForMapBitField() {
6146     return HObjectAccess(kInobject,
6147                          Map::kBitFieldOffset,
6148                          Representation::UInteger8());
6149   }
6150
6151   static HObjectAccess ForMapBitField2() {
6152     return HObjectAccess(kInobject,
6153                          Map::kBitField2Offset,
6154                          Representation::UInteger8());
6155   }
6156
6157   static HObjectAccess ForNameHashField() {
6158     return HObjectAccess(kInobject,
6159                          Name::kHashFieldOffset,
6160                          Representation::Integer32());
6161   }
6162
6163   static HObjectAccess ForMapInstanceTypeAndBitField() {
6164     STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6165     // Ensure the two fields share one 16-bit word, endian-independent.
6166     STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6167                   (Map::kInstanceTypeOffset & ~1));
6168     return HObjectAccess(kInobject,
6169                          Map::kInstanceTypeAndBitFieldOffset,
6170                          Representation::UInteger16());
6171   }
6172
6173   static HObjectAccess ForMapPrototype() {
6174     return HObjectAccess(kInobject, Map::kPrototypeOffset);
6175   }
6176
6177   static HObjectAccess ForPropertyCellValue() {
6178     return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6179   }
6180
6181   static HObjectAccess ForCellValue() {
6182     return HObjectAccess(kInobject, Cell::kValueOffset);
6183   }
6184
6185   static HObjectAccess ForAllocationMementoSite() {
6186     return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6187   }
6188
6189   static HObjectAccess ForCounter() {
6190     return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6191                          Handle<String>::null(), false, false);
6192   }
6193
6194   static HObjectAccess ForExternalUInteger8() {
6195     return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6196                          Handle<String>::null(), false, false);
6197   }
6198
6199   // Create an access to an offset in a fixed array header.
6200   static HObjectAccess ForFixedArrayHeader(int offset);
6201
6202   // Create an access to an in-object property in a JSObject.
6203   // This kind of access must be used when the object |map| is known and
6204   // in-object properties are being accessed. Accesses of the in-object
6205   // properties can have different semantics depending on whether corresponding
6206   // property was added to the map or not.
6207   static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6208       Representation representation = Representation::Tagged());
6209
6210   // Create an access to an in-object property in a JSObject.
6211   // This kind of access can be used for accessing object header fields or
6212   // in-object properties if the map of the object is not known.
6213   static HObjectAccess ForObservableJSObjectOffset(int offset,
6214       Representation representation = Representation::Tagged()) {
6215     return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6216   }
6217
6218   // Create an access to an in-object property in a JSArray.
6219   static HObjectAccess ForJSArrayOffset(int offset);
6220
6221   static HObjectAccess ForContextSlot(int index);
6222
6223   // Create an access to the backing store of an object.
6224   static HObjectAccess ForBackingStoreOffset(int offset,
6225       Representation representation = Representation::Tagged());
6226
6227   // Create an access to a resolved field (in-object or backing store).
6228   static HObjectAccess ForField(Handle<Map> map,
6229       LookupResult *lookup, Handle<String> name = Handle<String>::null());
6230
6231   // Create an access for the payload of a Cell or JSGlobalPropertyCell.
6232   static HObjectAccess ForCellPayload(Isolate* isolate);
6233
6234   static HObjectAccess ForJSTypedArrayLength() {
6235     return HObjectAccess::ForObservableJSObjectOffset(
6236         JSTypedArray::kLengthOffset);
6237   }
6238
6239   static HObjectAccess ForJSArrayBufferBackingStore() {
6240     return HObjectAccess::ForObservableJSObjectOffset(
6241         JSArrayBuffer::kBackingStoreOffset, Representation::External());
6242   }
6243
6244   static HObjectAccess ForJSArrayBufferByteLength() {
6245     return HObjectAccess::ForObservableJSObjectOffset(
6246         JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6247   }
6248
6249   static HObjectAccess ForExternalArrayExternalPointer() {
6250     return HObjectAccess::ForObservableJSObjectOffset(
6251         ExternalArray::kExternalPointerOffset, Representation::External());
6252   }
6253
6254   static HObjectAccess ForJSArrayBufferViewWeakNext() {
6255     return HObjectAccess::ForObservableJSObjectOffset(
6256         JSArrayBufferView::kWeakNextOffset);
6257   }
6258
6259   static HObjectAccess ForJSArrayBufferWeakFirstView() {
6260     return HObjectAccess::ForObservableJSObjectOffset(
6261         JSArrayBuffer::kWeakFirstViewOffset);
6262   }
6263
6264   static HObjectAccess ForJSArrayBufferViewBuffer() {
6265     return HObjectAccess::ForObservableJSObjectOffset(
6266         JSArrayBufferView::kBufferOffset);
6267   }
6268
6269   static HObjectAccess ForJSArrayBufferViewByteOffset() {
6270     return HObjectAccess::ForObservableJSObjectOffset(
6271         JSArrayBufferView::kByteOffsetOffset);
6272   }
6273
6274   static HObjectAccess ForJSArrayBufferViewByteLength() {
6275     return HObjectAccess::ForObservableJSObjectOffset(
6276         JSArrayBufferView::kByteLengthOffset);
6277   }
6278
6279   static HObjectAccess ForGlobalObjectNativeContext() {
6280     return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset);
6281   }
6282
6283   inline bool Equals(HObjectAccess that) const {
6284     return value_ == that.value_;  // portion and offset must match
6285   }
6286
6287  protected:
6288   void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6289
6290  private:
6291   // internal use only; different parts of an object or array
6292   enum Portion {
6293     kMaps,             // map of an object
6294     kArrayLengths,     // the length of an array
6295     kStringLengths,    // the length of a string
6296     kElementsPointer,  // elements pointer
6297     kBackingStore,     // some field in the backing store
6298     kDouble,           // some double field
6299     kInobject,         // some other in-object field
6300     kExternalMemory    // some field in external memory
6301   };
6302
6303   HObjectAccess() : value_(0) {}
6304
6305   HObjectAccess(Portion portion, int offset,
6306                 Representation representation = Representation::Tagged(),
6307                 Handle<String> name = Handle<String>::null(),
6308                 bool immutable = false,
6309                 bool existing_inobject_property = true)
6310     : value_(PortionField::encode(portion) |
6311              RepresentationField::encode(representation.kind()) |
6312              ImmutableField::encode(immutable ? 1 : 0) |
6313              ExistingInobjectPropertyField::encode(
6314                  existing_inobject_property ? 1 : 0) |
6315              OffsetField::encode(offset)),
6316       name_(name) {
6317     // assert that the fields decode correctly
6318     DCHECK(this->offset() == offset);
6319     DCHECK(this->portion() == portion);
6320     DCHECK(this->immutable() == immutable);
6321     DCHECK(this->existing_inobject_property() == existing_inobject_property);
6322     DCHECK(RepresentationField::decode(value_) == representation.kind());
6323     DCHECK(!this->existing_inobject_property() || IsInobject());
6324   }
6325
6326   class PortionField : public BitField<Portion, 0, 3> {};
6327   class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6328   class ImmutableField : public BitField<bool, 7, 1> {};
6329   class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6330   class OffsetField : public BitField<int, 9, 23> {};
6331
6332   uint32_t value_;  // encodes portion, representation, immutable, and offset
6333   Handle<String> name_;
6334
6335   friend class HLoadNamedField;
6336   friend class HStoreNamedField;
6337   friend class SideEffectsTracker;
6338   friend OStream& operator<<(OStream& os, const HObjectAccess& access);
6339
6340   inline Portion portion() const {
6341     return PortionField::decode(value_);
6342   }
6343 };
6344
6345
6346 OStream& operator<<(OStream& os, const HObjectAccess& access);
6347
6348
6349 class HLoadNamedField V8_FINAL : public HTemplateInstruction<2> {
6350  public:
6351   DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6352                                  HValue*, HObjectAccess);
6353   DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6354                                  HObjectAccess, const UniqueSet<Map>*, HType);
6355
6356   HValue* object() const { return OperandAt(0); }
6357   HValue* dependency() const {
6358     DCHECK(HasDependency());
6359     return OperandAt(1);
6360   }
6361   bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
6362   HObjectAccess access() const { return access_; }
6363   Representation field_representation() const {
6364       return access_.representation();
6365   }
6366
6367   const UniqueSet<Map>* maps() const { return maps_; }
6368
6369   virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
6370   virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
6371     return !access().IsInobject() || access().offset() >= size;
6372   }
6373   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6374     if (index == 0 && access().IsExternalMemory()) {
6375       // object must be external in case of external memory access
6376       return Representation::External();
6377     }
6378     return Representation::Tagged();
6379   }
6380   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
6381   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
6382
6383   bool CanBeReplacedWith(HValue* other) const {
6384     if (!CheckFlag(HValue::kCantBeReplaced)) return false;
6385     if (!type().Equals(other->type())) return false;
6386     if (!representation().Equals(other->representation())) return false;
6387     if (!other->IsLoadNamedField()) return true;
6388     HLoadNamedField* that = HLoadNamedField::cast(other);
6389     if (this->maps_ == that->maps_) return true;
6390     if (this->maps_ == NULL || that->maps_ == NULL) return false;
6391     return this->maps_->IsSubset(that->maps_);
6392   }
6393
6394   DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
6395
6396  protected:
6397   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
6398     HLoadNamedField* that = HLoadNamedField::cast(other);
6399     if (!this->access_.Equals(that->access_)) return false;
6400     if (this->maps_ == that->maps_) return true;
6401     return (this->maps_ != NULL &&
6402             that->maps_ != NULL &&
6403             this->maps_->Equals(that->maps_));
6404   }
6405
6406  private:
6407   HLoadNamedField(HValue* object,
6408                   HValue* dependency,
6409                   HObjectAccess access)
6410       : access_(access), maps_(NULL) {
6411     DCHECK_NOT_NULL(object);
6412     SetOperandAt(0, object);
6413     SetOperandAt(1, dependency ? dependency : object);
6414
6415     Representation representation = access.representation();
6416     if (representation.IsInteger8() ||
6417         representation.IsUInteger8() ||
6418         representation.IsInteger16() ||
6419         representation.IsUInteger16()) {
6420       set_representation(Representation::Integer32());
6421     } else if (representation.IsSmi()) {
6422       set_type(HType::Smi());
6423       if (SmiValuesAre32Bits()) {
6424         set_representation(Representation::Integer32());
6425       } else {
6426         set_representation(representation);
6427       }
6428     } else if (representation.IsDouble() ||
6429                representation.IsExternal() ||
6430                representation.IsInteger32()) {
6431       set_representation(representation);
6432     } else if (representation.IsHeapObject()) {
6433       set_type(HType::HeapObject());
6434       set_representation(Representation::Tagged());
6435     } else {
6436       set_representation(Representation::Tagged());
6437     }
6438     access.SetGVNFlags(this, LOAD);
6439   }
6440
6441   HLoadNamedField(HValue* object,
6442                   HValue* dependency,
6443                   HObjectAccess access,
6444                   const UniqueSet<Map>* maps,
6445                   HType type)
6446       : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
6447     DCHECK_NOT_NULL(maps);
6448     DCHECK_NE(0, maps->size());
6449
6450     DCHECK_NOT_NULL(object);
6451     SetOperandAt(0, object);
6452     SetOperandAt(1, dependency ? dependency : object);
6453
6454     DCHECK(access.representation().IsHeapObject());
6455     DCHECK(type.IsHeapObject());
6456     set_representation(Representation::Tagged());
6457
6458     access.SetGVNFlags(this, LOAD);
6459   }
6460
6461   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
6462
6463   HObjectAccess access_;
6464   const UniqueSet<Map>* maps_;
6465 };
6466
6467
6468 class HLoadNamedGeneric V8_FINAL : public HTemplateInstruction<2> {
6469  public:
6470   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadNamedGeneric, HValue*,
6471                                               Handle<Object>);
6472
6473   HValue* context() const { return OperandAt(0); }
6474   HValue* object() const { return OperandAt(1); }
6475   Handle<Object> name() const { return name_; }
6476
6477   int slot() const {
6478     DCHECK(FLAG_vector_ics &&
6479            slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
6480     return slot_;
6481   }
6482   Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
6483   void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
6484     DCHECK(FLAG_vector_ics);
6485     feedback_vector_ = vector;
6486     slot_ = slot;
6487   }
6488
6489   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6490     return Representation::Tagged();
6491   }
6492
6493   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
6494
6495   DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
6496
6497  private:
6498   HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
6499       : name_(name),
6500         slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
6501     SetOperandAt(0, context);
6502     SetOperandAt(1, object);
6503     set_representation(Representation::Tagged());
6504     SetAllSideEffects();
6505   }
6506
6507   Handle<Object> name_;
6508   Handle<FixedArray> feedback_vector_;
6509   int slot_;
6510 };
6511
6512
6513 class HLoadFunctionPrototype V8_FINAL : public HUnaryOperation {
6514  public:
6515   DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
6516
6517   HValue* function() { return OperandAt(0); }
6518
6519   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6520     return Representation::Tagged();
6521   }
6522
6523   DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
6524
6525  protected:
6526   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
6527
6528  private:
6529   explicit HLoadFunctionPrototype(HValue* function)
6530       : HUnaryOperation(function) {
6531     set_representation(Representation::Tagged());
6532     SetFlag(kUseGVN);
6533     SetDependsOnFlag(kCalls);
6534   }
6535 };
6536
6537 class ArrayInstructionInterface {
6538  public:
6539   virtual HValue* GetKey() = 0;
6540   virtual void SetKey(HValue* key) = 0;
6541   virtual ElementsKind elements_kind() const = 0;
6542   // TryIncreaseBaseOffset returns false if overflow would result.
6543   virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
6544   virtual bool IsDehoisted() const = 0;
6545   virtual void SetDehoisted(bool is_dehoisted) = 0;
6546   virtual ~ArrayInstructionInterface() { }
6547
6548   static Representation KeyedAccessIndexRequirement(Representation r) {
6549     return r.IsInteger32() || SmiValuesAre32Bits()
6550         ? Representation::Integer32() : Representation::Smi();
6551   }
6552 };
6553
6554
6555 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
6556
6557 enum LoadKeyedHoleMode {
6558   NEVER_RETURN_HOLE,
6559   ALLOW_RETURN_HOLE
6560 };
6561
6562
6563 class HLoadKeyed V8_FINAL
6564     : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6565  public:
6566   DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*,
6567                                  ElementsKind);
6568   DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*,
6569                                  ElementsKind, LoadKeyedHoleMode);
6570   DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*,
6571                                  ElementsKind, LoadKeyedHoleMode, int);
6572
6573   bool is_external() const {
6574     return IsExternalArrayElementsKind(elements_kind());
6575   }
6576   bool is_fixed_typed_array() const {
6577     return IsFixedTypedArrayElementsKind(elements_kind());
6578   }
6579   bool is_typed_elements() const {
6580     return is_external() || is_fixed_typed_array();
6581   }
6582   HValue* elements() const { return OperandAt(0); }
6583   HValue* key() const { return OperandAt(1); }
6584   HValue* dependency() const {
6585     DCHECK(HasDependency());
6586     return OperandAt(2);
6587   }
6588   bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
6589   uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
6590   bool TryIncreaseBaseOffset(uint32_t increase_by_value);
6591   HValue* GetKey() { return key(); }
6592   void SetKey(HValue* key) { SetOperandAt(1, key); }
6593   bool IsDehoisted() const { return IsDehoistedField::decode(bit_field_); }
6594   void SetDehoisted(bool is_dehoisted) {
6595     bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6596   }
6597   virtual ElementsKind elements_kind() const V8_OVERRIDE {
6598     return ElementsKindField::decode(bit_field_);
6599   }
6600   LoadKeyedHoleMode hole_mode() const {
6601     return HoleModeField::decode(bit_field_);
6602   }
6603
6604   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6605     // kind_fast:                 tagged[int32] (none)
6606     // kind_double:               tagged[int32] (none)
6607     // kind_fixed_typed_array:    tagged[int32] (none)
6608     // kind_external:             external[int32] (none)
6609     if (index == 0) {
6610       return is_external() ? Representation::External()
6611           : Representation::Tagged();
6612     }
6613     if (index == 1) {
6614       return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6615           OperandAt(1)->representation());
6616     }
6617     return Representation::None();
6618   }
6619
6620   virtual Representation observed_input_representation(int index) V8_OVERRIDE {
6621     return RequiredInputRepresentation(index);
6622   }
6623
6624   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
6625
6626   bool UsesMustHandleHole() const;
6627   bool AllUsesCanTreatHoleAsNaN() const;
6628   bool RequiresHoleCheck() const;
6629
6630   virtual Range* InferRange(Zone* zone) V8_OVERRIDE;
6631
6632   DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
6633
6634  protected:
6635   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
6636     if (!other->IsLoadKeyed()) return false;
6637     HLoadKeyed* other_load = HLoadKeyed::cast(other);
6638
6639     if (IsDehoisted() && base_offset() != other_load->base_offset())
6640       return false;
6641     return elements_kind() == other_load->elements_kind();
6642   }
6643
6644  private:
6645   HLoadKeyed(HValue* obj,
6646              HValue* key,
6647              HValue* dependency,
6648              ElementsKind elements_kind,
6649              LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
6650              int offset = kDefaultKeyedHeaderOffsetSentinel)
6651       : bit_field_(0) {
6652     offset = offset == kDefaultKeyedHeaderOffsetSentinel
6653         ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6654         : offset;
6655     bit_field_ = ElementsKindField::encode(elements_kind) |
6656         HoleModeField::encode(mode) |
6657         BaseOffsetField::encode(offset);
6658
6659     SetOperandAt(0, obj);
6660     SetOperandAt(1, key);
6661     SetOperandAt(2, dependency != NULL ? dependency : obj);
6662
6663     if (!is_typed_elements()) {
6664       // I can detect the case between storing double (holey and fast) and
6665       // smi/object by looking at elements_kind_.
6666       DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
6667              IsFastDoubleElementsKind(elements_kind));
6668
6669       if (IsFastSmiOrObjectElementsKind(elements_kind)) {
6670         if (IsFastSmiElementsKind(elements_kind) &&
6671             (!IsHoleyElementsKind(elements_kind) ||
6672              mode == NEVER_RETURN_HOLE)) {
6673           set_type(HType::Smi());
6674           if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
6675             set_representation(Representation::Integer32());
6676           } else {
6677             set_representation(Representation::Smi());
6678           }
6679         } else {
6680           set_representation(Representation::Tagged());
6681         }
6682
6683         SetDependsOnFlag(kArrayElements);
6684       } else {
6685         set_representation(Representation::Double());
6686         SetDependsOnFlag(kDoubleArrayElements);
6687       }
6688     } else {
6689       if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
6690           elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
6691           elements_kind == FLOAT32_ELEMENTS ||
6692           elements_kind == FLOAT64_ELEMENTS) {
6693         set_representation(Representation::Double());
6694       } else if (IsFloat32x4ElementsKind(elements_kind)) {
6695         set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6696             Representation::Float32x4() : Representation::Tagged());
6697       } else if (IsFloat64x2ElementsKind(elements_kind)) {
6698         set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6699             Representation::Float64x2() : Representation::Tagged());
6700       } else if (IsInt32x4ElementsKind(elements_kind)) {
6701         set_representation(CpuFeatures::SupportsSIMD128InCrankshaft() ?
6702             Representation::Int32x4() : Representation::Tagged());
6703       } else {
6704         set_representation(Representation::Integer32());
6705       }
6706
6707       if (is_external()) {
6708         SetDependsOnFlag(kExternalMemory);
6709       } else if (is_fixed_typed_array()) {
6710         SetDependsOnFlag(kTypedArrayElements);
6711       } else {
6712         UNREACHABLE();
6713       }
6714       // Native code could change the specialized array.
6715       SetDependsOnFlag(kCalls);
6716     }
6717
6718     SetFlag(kUseGVN);
6719   }
6720
6721   virtual bool IsDeletable() const V8_OVERRIDE {
6722     return !RequiresHoleCheck();
6723   }
6724
6725   // Establish some checks around our packed fields
6726   enum LoadKeyedBits {
6727     kBitsForElementsKind = 5,
6728     kBitsForHoleMode = 1,
6729     kBitsForBaseOffset = 25,
6730     kBitsForIsDehoisted = 1,
6731
6732     kStartElementsKind = 0,
6733     kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
6734     kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
6735     kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
6736   };
6737
6738   STATIC_ASSERT((kBitsForElementsKind + kBitsForBaseOffset +
6739                  kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
6740   STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
6741   class ElementsKindField:
6742     public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
6743     {};  // NOLINT
6744   class HoleModeField:
6745     public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
6746     {};  // NOLINT
6747   class BaseOffsetField:
6748     public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
6749     {};  // NOLINT
6750   class IsDehoistedField:
6751     public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
6752     {};  // NOLINT
6753   uint32_t bit_field_;
6754 };
6755
6756
6757 class HLoadKeyedGeneric V8_FINAL : public HTemplateInstruction<3> {
6758  public:
6759   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadKeyedGeneric, HValue*,
6760                                               HValue*);
6761   HValue* object() const { return OperandAt(0); }
6762   HValue* key() const { return OperandAt(1); }
6763   HValue* context() const { return OperandAt(2); }
6764   int slot() const {
6765     DCHECK(FLAG_vector_ics &&
6766            slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
6767     return slot_;
6768   }
6769   Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
6770   void SetVectorAndSlot(Handle<FixedArray> vector, int slot) {
6771     DCHECK(FLAG_vector_ics);
6772     feedback_vector_ = vector;
6773     slot_ = slot;
6774   }
6775
6776   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
6777
6778   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6779     // tagged[tagged]
6780     return Representation::Tagged();
6781   }
6782
6783   virtual HValue* Canonicalize() V8_OVERRIDE;
6784
6785   DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
6786
6787  private:
6788   HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
6789       : slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) {
6790     set_representation(Representation::Tagged());
6791     SetOperandAt(0, obj);
6792     SetOperandAt(1, key);
6793     SetOperandAt(2, context);
6794     SetAllSideEffects();
6795   }
6796
6797   Handle<FixedArray> feedback_vector_;
6798   int slot_;
6799 };
6800
6801
6802 // Indicates whether the store is a store to an entry that was previously
6803 // initialized or not.
6804 enum StoreFieldOrKeyedMode {
6805   // The entry could be either previously initialized or not.
6806   INITIALIZING_STORE,
6807   // At the time of this store it is guaranteed that the entry is already
6808   // initialized.
6809   STORE_TO_INITIALIZED_ENTRY
6810 };
6811
6812
6813 class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
6814  public:
6815   DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
6816                                  HObjectAccess, HValue*);
6817   DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
6818                                  HObjectAccess, HValue*, StoreFieldOrKeyedMode);
6819
6820   DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
6821
6822   virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE {
6823     return index == 1;
6824   }
6825   virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
6826     return !access().IsInobject() || access().offset() >= size;
6827   }
6828   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6829     if (index == 0 && access().IsExternalMemory()) {
6830       // object must be external in case of external memory access
6831       return Representation::External();
6832     } else if (index == 1) {
6833       if (field_representation().IsInteger8() ||
6834           field_representation().IsUInteger8() ||
6835           field_representation().IsInteger16() ||
6836           field_representation().IsUInteger16() ||
6837           field_representation().IsInteger32()) {
6838         return Representation::Integer32();
6839       } else if (field_representation().IsDouble()) {
6840         return field_representation();
6841       } else if (field_representation().IsSmi()) {
6842         if (SmiValuesAre32Bits() && store_mode_ == STORE_TO_INITIALIZED_ENTRY) {
6843           return Representation::Integer32();
6844         }
6845         return field_representation();
6846       } else if (field_representation().IsExternal()) {
6847         return Representation::External();
6848       }
6849     }
6850     return Representation::Tagged();
6851   }
6852   virtual bool HandleSideEffectDominator(GVNFlag side_effect,
6853                                          HValue* dominator) V8_OVERRIDE {
6854     DCHECK(side_effect == kNewSpacePromotion);
6855     if (!FLAG_use_write_barrier_elimination) return false;
6856     dominator_ = dominator;
6857     return false;
6858   }
6859   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
6860
6861   HValue* object() const { return OperandAt(0); }
6862   HValue* value() const { return OperandAt(1); }
6863   HValue* transition() const { return OperandAt(2); }
6864
6865   HObjectAccess access() const { return access_; }
6866   HValue* dominator() const { return dominator_; }
6867   bool has_transition() const { return has_transition_; }
6868   StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
6869
6870   Handle<Map> transition_map() const {
6871     if (has_transition()) {
6872       return Handle<Map>::cast(
6873           HConstant::cast(transition())->handle(Isolate::Current()));
6874     } else {
6875       return Handle<Map>();
6876     }
6877   }
6878
6879   void SetTransition(HConstant* transition) {
6880     DCHECK(!has_transition());  // Only set once.
6881     SetOperandAt(2, transition);
6882     has_transition_ = true;
6883     SetChangesFlag(kMaps);
6884   }
6885
6886   bool NeedsWriteBarrier() const {
6887     DCHECK(!field_representation().IsDouble() || !has_transition());
6888     if (field_representation().IsDouble()) return false;
6889     if (field_representation().IsSmi()) return false;
6890     if (field_representation().IsInteger32()) return false;
6891     if (field_representation().IsExternal()) return false;
6892     return StoringValueNeedsWriteBarrier(value()) &&
6893         ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
6894   }
6895
6896   bool NeedsWriteBarrierForMap() {
6897     return ReceiverObjectNeedsWriteBarrier(object(), transition(),
6898                                            dominator());
6899   }
6900
6901   SmiCheck SmiCheckForWriteBarrier() const {
6902     if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
6903     if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
6904     return INLINE_SMI_CHECK;
6905   }
6906
6907   PointersToHereCheck PointersToHereCheckForValue() const {
6908     return PointersToHereCheckForObject(value(), dominator());
6909   }
6910
6911   Representation field_representation() const {
6912     return access_.representation();
6913   }
6914
6915   void UpdateValue(HValue* value) {
6916     SetOperandAt(1, value);
6917   }
6918
6919   bool CanBeReplacedWith(HStoreNamedField* that) const {
6920     if (!this->access().Equals(that->access())) return false;
6921     if (SmiValuesAre32Bits() &&
6922         this->field_representation().IsSmi() &&
6923         this->store_mode() == INITIALIZING_STORE &&
6924         that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6925       // We cannot replace an initializing store to a smi field with a store to
6926       // an initialized entry on 64-bit architectures (with 32-bit smis).
6927       return false;
6928     }
6929     return true;
6930   }
6931
6932  private:
6933   HStoreNamedField(HValue* obj,
6934                    HObjectAccess access,
6935                    HValue* val,
6936                    StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
6937       : access_(access),
6938         dominator_(NULL),
6939         has_transition_(false),
6940         store_mode_(store_mode) {
6941     // Stores to a non existing in-object property are allowed only to the
6942     // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6943     DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6944            obj->IsAllocate() || obj->IsInnerAllocatedObject());
6945     SetOperandAt(0, obj);
6946     SetOperandAt(1, val);
6947     SetOperandAt(2, obj);
6948     access.SetGVNFlags(this, STORE);
6949   }
6950
6951   HObjectAccess access_;
6952   HValue* dominator_;
6953   bool has_transition_ : 1;
6954   StoreFieldOrKeyedMode store_mode_ : 1;
6955 };
6956
6957
6958 class HStoreNamedGeneric V8_FINAL : public HTemplateInstruction<3> {
6959  public:
6960   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreNamedGeneric, HValue*,
6961                                               Handle<String>, HValue*,
6962                                               StrictMode);
6963   HValue* object() const { return OperandAt(0); }
6964   HValue* value() const { return OperandAt(1); }
6965   HValue* context() const { return OperandAt(2); }
6966   Handle<String> name() const { return name_; }
6967   StrictMode strict_mode() const { return strict_mode_; }
6968
6969   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
6970
6971   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
6972     return Representation::Tagged();
6973   }
6974
6975   DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
6976
6977  private:
6978   HStoreNamedGeneric(HValue* context,
6979                      HValue* object,
6980                      Handle<String> name,
6981                      HValue* value,
6982                      StrictMode strict_mode)
6983       : name_(name),
6984         strict_mode_(strict_mode) {
6985     SetOperandAt(0, object);
6986     SetOperandAt(1, value);
6987     SetOperandAt(2, context);
6988     SetAllSideEffects();
6989   }
6990
6991   Handle<String> name_;
6992   StrictMode strict_mode_;
6993 };
6994
6995
6996 class HStoreKeyed V8_FINAL
6997     : public HTemplateInstruction<3>, public ArrayInstructionInterface {
6998  public:
6999   DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*,
7000                                  ElementsKind);
7001   DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
7002                                  ElementsKind, StoreFieldOrKeyedMode);
7003   DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
7004                                  ElementsKind, StoreFieldOrKeyedMode, int);
7005
7006   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7007     // kind_fast:               tagged[int32] = tagged
7008     // kind_double:             tagged[int32] = double
7009     // kind_smi   :             tagged[int32] = smi
7010     // kind_fixed_typed_array:  tagged[int32] = (double | int32)
7011     // kind_external:           external[int32] = (double | int32)
7012     if (index == 0) {
7013       return is_external() ? Representation::External()
7014                            : Representation::Tagged();
7015     } else if (index == 1) {
7016       return ArrayInstructionInterface::KeyedAccessIndexRequirement(
7017           OperandAt(1)->representation());
7018     }
7019
7020     DCHECK_EQ(index, 2);
7021     return RequiredValueRepresentation(elements_kind_, store_mode_);
7022   }
7023
7024   static Representation RequiredValueRepresentation(
7025       ElementsKind kind, StoreFieldOrKeyedMode mode) {
7026     if (IsDoubleOrFloatElementsKind(kind)) {
7027       return Representation::Double();
7028     }
7029
7030     if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
7031         mode == STORE_TO_INITIALIZED_ENTRY) {
7032       return Representation::Integer32();
7033     }
7034
7035     if (IsFloat32x4ElementsKind(kind)) {
7036       return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7037           Representation::Float32x4() : Representation::Tagged();
7038     }
7039     if (IsFloat64x2ElementsKind(kind)) {
7040       return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7041           Representation::Float64x2() : Representation::Tagged();
7042     }
7043     if (IsInt32x4ElementsKind(kind)) {
7044       return CpuFeatures::SupportsSIMD128InCrankshaft() ?
7045           Representation::Int32x4() : Representation::Tagged();
7046     }
7047
7048     if (IsFastSmiElementsKind(kind)) {
7049       return Representation::Smi();
7050     }
7051
7052     return IsExternalArrayElementsKind(kind) ||
7053                    IsFixedTypedArrayElementsKind(kind)
7054                ? Representation::Integer32()
7055                : Representation::Tagged();
7056   }
7057
7058   bool is_external() const {
7059     return IsExternalArrayElementsKind(elements_kind());
7060   }
7061
7062   bool is_fixed_typed_array() const {
7063     return IsFixedTypedArrayElementsKind(elements_kind());
7064   }
7065
7066   bool is_typed_elements() const {
7067     return is_external() || is_fixed_typed_array();
7068   }
7069
7070   virtual Representation observed_input_representation(int index) V8_OVERRIDE {
7071     if (index < 2) return RequiredInputRepresentation(index);
7072     if (IsUninitialized()) {
7073       return Representation::None();
7074     }
7075     Representation r = RequiredValueRepresentation(elements_kind_, store_mode_);
7076     // For fast object elements kinds, don't assume anything.
7077     if (r.IsTagged()) return Representation::None();
7078     return r;
7079   }
7080
7081   HValue* elements() const { return OperandAt(0); }
7082   HValue* key() const { return OperandAt(1); }
7083   HValue* value() const { return OperandAt(2); }
7084   bool value_is_smi() const {
7085     return IsFastSmiElementsKind(elements_kind_);
7086   }
7087   StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
7088   ElementsKind elements_kind() const { return elements_kind_; }
7089   uint32_t base_offset() const { return base_offset_; }
7090   bool TryIncreaseBaseOffset(uint32_t increase_by_value);
7091   HValue* GetKey() { return key(); }
7092   void SetKey(HValue* key) { SetOperandAt(1, key); }
7093   bool IsDehoisted() const { return is_dehoisted_; }
7094   void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
7095   bool IsUninitialized() { return is_uninitialized_; }
7096   void SetUninitialized(bool is_uninitialized) {
7097     is_uninitialized_ = is_uninitialized;
7098   }
7099
7100   bool IsConstantHoleStore() {
7101     return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
7102   }
7103
7104   virtual bool HandleSideEffectDominator(GVNFlag side_effect,
7105                                          HValue* dominator) V8_OVERRIDE {
7106     DCHECK(side_effect == kNewSpacePromotion);
7107     dominator_ = dominator;
7108     return false;
7109   }
7110
7111   HValue* dominator() const { return dominator_; }
7112
7113   bool NeedsWriteBarrier() {
7114     if (value_is_smi()) {
7115       return false;
7116     } else {
7117       return StoringValueNeedsWriteBarrier(value()) &&
7118           ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
7119     }
7120   }
7121
7122   PointersToHereCheck PointersToHereCheckForValue() const {
7123     return PointersToHereCheckForObject(value(), dominator());
7124   }
7125
7126   bool NeedsCanonicalization();
7127
7128   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
7129
7130   DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
7131
7132  private:
7133   HStoreKeyed(HValue* obj, HValue* key, HValue* val,
7134               ElementsKind elements_kind,
7135               StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
7136               int offset = kDefaultKeyedHeaderOffsetSentinel)
7137       : elements_kind_(elements_kind),
7138       base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
7139           ? GetDefaultHeaderSizeForElementsKind(elements_kind)
7140           : offset),
7141       is_dehoisted_(false),
7142       is_uninitialized_(false),
7143       store_mode_(store_mode),
7144       dominator_(NULL) {
7145     SetOperandAt(0, obj);
7146     SetOperandAt(1, key);
7147     SetOperandAt(2, val);
7148
7149     if (IsFastObjectElementsKind(elements_kind)) {
7150       SetFlag(kTrackSideEffectDominators);
7151       SetDependsOnFlag(kNewSpacePromotion);
7152     }
7153     if (is_external()) {
7154       SetChangesFlag(kExternalMemory);
7155       SetFlag(kAllowUndefinedAsNaN);
7156     } else if (IsFastDoubleElementsKind(elements_kind)) {
7157       SetChangesFlag(kDoubleArrayElements);
7158     } else if (IsFastSmiElementsKind(elements_kind)) {
7159       SetChangesFlag(kArrayElements);
7160     } else if (is_fixed_typed_array()) {
7161       SetChangesFlag(kTypedArrayElements);
7162       SetFlag(kAllowUndefinedAsNaN);
7163     } else {
7164       SetChangesFlag(kArrayElements);
7165     }
7166
7167     // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
7168     if ((elements_kind >= EXTERNAL_INT8_ELEMENTS &&
7169         elements_kind <= EXTERNAL_UINT32_ELEMENTS) ||
7170         (elements_kind >= UINT8_ELEMENTS &&
7171         elements_kind <= INT32_ELEMENTS)) {
7172       SetFlag(kTruncatingToInt32);
7173     }
7174   }
7175
7176   ElementsKind elements_kind_;
7177   uint32_t base_offset_;
7178   bool is_dehoisted_ : 1;
7179   bool is_uninitialized_ : 1;
7180   StoreFieldOrKeyedMode store_mode_: 1;
7181   HValue* dominator_;
7182 };
7183
7184
7185 class HStoreKeyedGeneric V8_FINAL : public HTemplateInstruction<4> {
7186  public:
7187   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreKeyedGeneric, HValue*,
7188                                               HValue*, HValue*, StrictMode);
7189
7190   HValue* object() const { return OperandAt(0); }
7191   HValue* key() const { return OperandAt(1); }
7192   HValue* value() const { return OperandAt(2); }
7193   HValue* context() const { return OperandAt(3); }
7194   StrictMode strict_mode() const { return strict_mode_; }
7195
7196   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7197     // tagged[tagged] = tagged
7198     return Representation::Tagged();
7199   }
7200
7201   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
7202
7203   DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
7204
7205  private:
7206   HStoreKeyedGeneric(HValue* context,
7207                      HValue* object,
7208                      HValue* key,
7209                      HValue* value,
7210                      StrictMode strict_mode)
7211       : strict_mode_(strict_mode) {
7212     SetOperandAt(0, object);
7213     SetOperandAt(1, key);
7214     SetOperandAt(2, value);
7215     SetOperandAt(3, context);
7216     SetAllSideEffects();
7217   }
7218
7219   StrictMode strict_mode_;
7220 };
7221
7222
7223 class HTransitionElementsKind V8_FINAL : public HTemplateInstruction<2> {
7224  public:
7225   inline static HTransitionElementsKind* New(Zone* zone,
7226                                              HValue* context,
7227                                              HValue* object,
7228                                              Handle<Map> original_map,
7229                                              Handle<Map> transitioned_map) {
7230     return new(zone) HTransitionElementsKind(context, object,
7231                                              original_map, transitioned_map);
7232   }
7233
7234   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7235     return Representation::Tagged();
7236   }
7237
7238   HValue* object() const { return OperandAt(0); }
7239   HValue* context() const { return OperandAt(1); }
7240   Unique<Map> original_map() const { return original_map_; }
7241   Unique<Map> transitioned_map() const { return transitioned_map_; }
7242   ElementsKind from_kind() const { return from_kind_; }
7243   ElementsKind to_kind() const { return to_kind_; }
7244
7245   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
7246
7247   DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
7248
7249  protected:
7250   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7251     HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
7252     return original_map_ == instr->original_map_ &&
7253            transitioned_map_ == instr->transitioned_map_;
7254   }
7255
7256   virtual int RedefinedOperandIndex() { return 0; }
7257
7258  private:
7259   HTransitionElementsKind(HValue* context,
7260                           HValue* object,
7261                           Handle<Map> original_map,
7262                           Handle<Map> transitioned_map)
7263       : original_map_(Unique<Map>(original_map)),
7264         transitioned_map_(Unique<Map>(transitioned_map)),
7265         from_kind_(original_map->elements_kind()),
7266         to_kind_(transitioned_map->elements_kind()) {
7267     SetOperandAt(0, object);
7268     SetOperandAt(1, context);
7269     SetFlag(kUseGVN);
7270     SetChangesFlag(kElementsKind);
7271     if (!IsSimpleMapChangeTransition(from_kind_, to_kind_)) {
7272       SetChangesFlag(kElementsPointer);
7273       SetChangesFlag(kNewSpacePromotion);
7274     }
7275     set_representation(Representation::Tagged());
7276   }
7277
7278   Unique<Map> original_map_;
7279   Unique<Map> transitioned_map_;
7280   ElementsKind from_kind_;
7281   ElementsKind to_kind_;
7282 };
7283
7284
7285 class HStringAdd V8_FINAL : public HBinaryOperation {
7286  public:
7287   static HInstruction* New(Zone* zone,
7288                            HValue* context,
7289                            HValue* left,
7290                            HValue* right,
7291                            PretenureFlag pretenure_flag = NOT_TENURED,
7292                            StringAddFlags flags = STRING_ADD_CHECK_BOTH,
7293                            Handle<AllocationSite> allocation_site =
7294                                Handle<AllocationSite>::null());
7295
7296   StringAddFlags flags() const { return flags_; }
7297   PretenureFlag pretenure_flag() const { return pretenure_flag_; }
7298
7299   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7300     return Representation::Tagged();
7301   }
7302
7303   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
7304
7305   DECLARE_CONCRETE_INSTRUCTION(StringAdd)
7306
7307  protected:
7308   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7309     return flags_ == HStringAdd::cast(other)->flags_ &&
7310         pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
7311   }
7312
7313  private:
7314   HStringAdd(HValue* context,
7315              HValue* left,
7316              HValue* right,
7317              PretenureFlag pretenure_flag,
7318              StringAddFlags flags,
7319              Handle<AllocationSite> allocation_site)
7320       : HBinaryOperation(context, left, right, HType::String()),
7321         flags_(flags), pretenure_flag_(pretenure_flag) {
7322     set_representation(Representation::Tagged());
7323     SetFlag(kUseGVN);
7324     SetDependsOnFlag(kMaps);
7325     SetChangesFlag(kNewSpacePromotion);
7326     if (FLAG_trace_pretenuring) {
7327       PrintF("HStringAdd with AllocationSite %p %s\n",
7328              allocation_site.is_null()
7329                  ? static_cast<void*>(NULL)
7330                  : static_cast<void*>(*allocation_site),
7331              pretenure_flag == TENURED ? "tenured" : "not tenured");
7332     }
7333   }
7334
7335   // No side-effects except possible allocation:
7336   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7337
7338   const StringAddFlags flags_;
7339   const PretenureFlag pretenure_flag_;
7340 };
7341
7342
7343 class HStringCharCodeAt V8_FINAL : public HTemplateInstruction<3> {
7344  public:
7345   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
7346                                               HValue*,
7347                                               HValue*);
7348
7349   virtual Representation RequiredInputRepresentation(int index) {
7350     // The index is supposed to be Integer32.
7351     return index == 2
7352         ? Representation::Integer32()
7353         : Representation::Tagged();
7354   }
7355
7356   HValue* context() const { return OperandAt(0); }
7357   HValue* string() const { return OperandAt(1); }
7358   HValue* index() const { return OperandAt(2); }
7359
7360   DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
7361
7362  protected:
7363   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
7364
7365   virtual Range* InferRange(Zone* zone) V8_OVERRIDE {
7366     return new(zone) Range(0, String::kMaxUtf16CodeUnit);
7367   }
7368
7369  private:
7370   HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
7371     SetOperandAt(0, context);
7372     SetOperandAt(1, string);
7373     SetOperandAt(2, index);
7374     set_representation(Representation::Integer32());
7375     SetFlag(kUseGVN);
7376     SetDependsOnFlag(kMaps);
7377     SetDependsOnFlag(kStringChars);
7378     SetChangesFlag(kNewSpacePromotion);
7379   }
7380
7381   // No side effects: runtime function assumes string + number inputs.
7382   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7383 };
7384
7385
7386 class HStringCharFromCode V8_FINAL : public HTemplateInstruction<2> {
7387  public:
7388   static HInstruction* New(Zone* zone,
7389                            HValue* context,
7390                            HValue* char_code);
7391
7392   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7393     return index == 0
7394         ? Representation::Tagged()
7395         : Representation::Integer32();
7396   }
7397
7398   HValue* context() const { return OperandAt(0); }
7399   HValue* value() const { return OperandAt(1); }
7400
7401   virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; }
7402
7403   DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
7404
7405  private:
7406   HStringCharFromCode(HValue* context, HValue* char_code)
7407       : HTemplateInstruction<2>(HType::String()) {
7408     SetOperandAt(0, context);
7409     SetOperandAt(1, char_code);
7410     set_representation(Representation::Tagged());
7411     SetFlag(kUseGVN);
7412     SetChangesFlag(kNewSpacePromotion);
7413   }
7414
7415   virtual bool IsDeletable() const V8_OVERRIDE {
7416     return !value()->ToNumberCanBeObserved();
7417   }
7418 };
7419
7420
7421 template <int V>
7422 class HMaterializedLiteral : public HTemplateInstruction<V> {
7423  public:
7424   HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
7425       : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
7426     this->set_representation(Representation::Tagged());
7427   }
7428
7429   HMaterializedLiteral<V>(int index, int depth)
7430       : literal_index_(index), depth_(depth),
7431         allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
7432     this->set_representation(Representation::Tagged());
7433   }
7434
7435   int literal_index() const { return literal_index_; }
7436   int depth() const { return depth_; }
7437   AllocationSiteMode allocation_site_mode() const {
7438     return allocation_site_mode_;
7439   }
7440
7441  private:
7442   virtual bool IsDeletable() const V8_FINAL V8_OVERRIDE { return true; }
7443
7444   int literal_index_;
7445   int depth_;
7446   AllocationSiteMode allocation_site_mode_;
7447 };
7448
7449
7450 class HRegExpLiteral V8_FINAL : public HMaterializedLiteral<1> {
7451  public:
7452   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral,
7453                                               Handle<FixedArray>,
7454                                               Handle<String>,
7455                                               Handle<String>,
7456                                               int);
7457
7458   HValue* context() { return OperandAt(0); }
7459   Handle<FixedArray> literals() { return literals_; }
7460   Handle<String> pattern() { return pattern_; }
7461   Handle<String> flags() { return flags_; }
7462
7463   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7464     return Representation::Tagged();
7465   }
7466
7467   DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
7468
7469  private:
7470   HRegExpLiteral(HValue* context,
7471                  Handle<FixedArray> literals,
7472                  Handle<String> pattern,
7473                  Handle<String> flags,
7474                  int literal_index)
7475       : HMaterializedLiteral<1>(literal_index, 0),
7476         literals_(literals),
7477         pattern_(pattern),
7478         flags_(flags) {
7479     SetOperandAt(0, context);
7480     SetAllSideEffects();
7481     set_type(HType::JSObject());
7482   }
7483
7484   Handle<FixedArray> literals_;
7485   Handle<String> pattern_;
7486   Handle<String> flags_;
7487 };
7488
7489
7490 class HFunctionLiteral V8_FINAL : public HTemplateInstruction<1> {
7491  public:
7492   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HFunctionLiteral,
7493                                               Handle<SharedFunctionInfo>,
7494                                               bool);
7495   HValue* context() { return OperandAt(0); }
7496
7497   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7498     return Representation::Tagged();
7499   }
7500
7501   DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
7502
7503   Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
7504   bool pretenure() const { return pretenure_; }
7505   bool has_no_literals() const { return has_no_literals_; }
7506   bool is_generator() const { return is_generator_; }
7507   StrictMode strict_mode() const { return strict_mode_; }
7508
7509  private:
7510   HFunctionLiteral(HValue* context,
7511                    Handle<SharedFunctionInfo> shared,
7512                    bool pretenure)
7513       : HTemplateInstruction<1>(HType::JSObject()),
7514         shared_info_(shared),
7515         pretenure_(pretenure),
7516         has_no_literals_(shared->num_literals() == 0),
7517         is_generator_(shared->is_generator()),
7518         strict_mode_(shared->strict_mode()) {
7519     SetOperandAt(0, context);
7520     set_representation(Representation::Tagged());
7521     SetChangesFlag(kNewSpacePromotion);
7522   }
7523
7524   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7525
7526   Handle<SharedFunctionInfo> shared_info_;
7527   bool pretenure_ : 1;
7528   bool has_no_literals_ : 1;
7529   bool is_generator_ : 1;
7530   StrictMode strict_mode_;
7531 };
7532
7533
7534 class HTypeof V8_FINAL : public HTemplateInstruction<2> {
7535  public:
7536   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*);
7537
7538   HValue* context() const { return OperandAt(0); }
7539   HValue* value() const { return OperandAt(1); }
7540
7541   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
7542
7543   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7544     return Representation::Tagged();
7545   }
7546
7547   DECLARE_CONCRETE_INSTRUCTION(Typeof)
7548
7549  private:
7550   explicit HTypeof(HValue* context, HValue* value) {
7551     SetOperandAt(0, context);
7552     SetOperandAt(1, value);
7553     set_representation(Representation::Tagged());
7554   }
7555
7556   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7557 };
7558
7559
7560 class HTrapAllocationMemento V8_FINAL : public HTemplateInstruction<1> {
7561  public:
7562   DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*);
7563
7564   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7565     return Representation::Tagged();
7566   }
7567
7568   HValue* object() { return OperandAt(0); }
7569
7570   DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
7571
7572  private:
7573   explicit HTrapAllocationMemento(HValue* obj) {
7574     SetOperandAt(0, obj);
7575   }
7576 };
7577
7578
7579 class HToFastProperties V8_FINAL : public HUnaryOperation {
7580  public:
7581   DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*);
7582
7583   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7584     return Representation::Tagged();
7585   }
7586
7587   DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
7588
7589  private:
7590   explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
7591     set_representation(Representation::Tagged());
7592     SetChangesFlag(kNewSpacePromotion);
7593
7594     // This instruction is not marked as kChangesMaps, but does
7595     // change the map of the input operand. Use it only when creating
7596     // object literals via a runtime call.
7597     DCHECK(value->IsCallRuntime());
7598 #ifdef DEBUG
7599     const Runtime::Function* function = HCallRuntime::cast(value)->function();
7600     DCHECK(function->function_id == Runtime::kCreateObjectLiteral);
7601 #endif
7602   }
7603
7604   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7605 };
7606
7607
7608 class HDateField V8_FINAL : public HUnaryOperation {
7609  public:
7610   DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*);
7611
7612   Smi* index() const { return index_; }
7613
7614   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7615     return Representation::Tagged();
7616   }
7617
7618   DECLARE_CONCRETE_INSTRUCTION(DateField)
7619
7620  private:
7621   HDateField(HValue* date, Smi* index)
7622       : HUnaryOperation(date), index_(index) {
7623     set_representation(Representation::Tagged());
7624   }
7625
7626   Smi* index_;
7627 };
7628
7629
7630 class HSeqStringGetChar V8_FINAL : public HTemplateInstruction<2> {
7631  public:
7632   static HInstruction* New(Zone* zone,
7633                            HValue* context,
7634                            String::Encoding encoding,
7635                            HValue* string,
7636                            HValue* index);
7637
7638   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7639     return (index == 0) ? Representation::Tagged()
7640                         : Representation::Integer32();
7641   }
7642
7643   String::Encoding encoding() const { return encoding_; }
7644   HValue* string() const { return OperandAt(0); }
7645   HValue* index() const { return OperandAt(1); }
7646
7647   DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar)
7648
7649  protected:
7650   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7651     return encoding() == HSeqStringGetChar::cast(other)->encoding();
7652   }
7653
7654   virtual Range* InferRange(Zone* zone) V8_OVERRIDE {
7655     if (encoding() == String::ONE_BYTE_ENCODING) {
7656       return new(zone) Range(0, String::kMaxOneByteCharCode);
7657     } else {
7658       DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding());
7659       return  new(zone) Range(0, String::kMaxUtf16CodeUnit);
7660     }
7661   }
7662
7663  private:
7664   HSeqStringGetChar(String::Encoding encoding,
7665                     HValue* string,
7666                     HValue* index) : encoding_(encoding) {
7667     SetOperandAt(0, string);
7668     SetOperandAt(1, index);
7669     set_representation(Representation::Integer32());
7670     SetFlag(kUseGVN);
7671     SetDependsOnFlag(kStringChars);
7672   }
7673
7674   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7675
7676   String::Encoding encoding_;
7677 };
7678
7679
7680 class HSeqStringSetChar V8_FINAL : public HTemplateInstruction<4> {
7681  public:
7682   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(
7683       HSeqStringSetChar, String::Encoding,
7684       HValue*, HValue*, HValue*);
7685
7686   String::Encoding encoding() { return encoding_; }
7687   HValue* context() { return OperandAt(0); }
7688   HValue* string() { return OperandAt(1); }
7689   HValue* index() { return OperandAt(2); }
7690   HValue* value() { return OperandAt(3); }
7691
7692   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7693     return (index <= 1) ? Representation::Tagged()
7694                         : Representation::Integer32();
7695   }
7696
7697   DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
7698
7699  private:
7700   HSeqStringSetChar(HValue* context,
7701                     String::Encoding encoding,
7702                     HValue* string,
7703                     HValue* index,
7704                     HValue* value) : encoding_(encoding) {
7705     SetOperandAt(0, context);
7706     SetOperandAt(1, string);
7707     SetOperandAt(2, index);
7708     SetOperandAt(3, value);
7709     set_representation(Representation::Tagged());
7710     SetChangesFlag(kStringChars);
7711   }
7712
7713   String::Encoding encoding_;
7714 };
7715
7716
7717 class HCheckMapValue V8_FINAL : public HTemplateInstruction<2> {
7718  public:
7719   DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*);
7720
7721   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7722     return Representation::Tagged();
7723   }
7724
7725   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
7726
7727   virtual HType CalculateInferredType() V8_OVERRIDE {
7728     if (value()->type().IsHeapObject()) return value()->type();
7729     return HType::HeapObject();
7730   }
7731
7732   HValue* value() const { return OperandAt(0); }
7733   HValue* map() const { return OperandAt(1); }
7734
7735   virtual HValue* Canonicalize() V8_OVERRIDE;
7736
7737   DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
7738
7739  protected:
7740   virtual int RedefinedOperandIndex() { return 0; }
7741
7742   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7743     return true;
7744   }
7745
7746  private:
7747   HCheckMapValue(HValue* value, HValue* map)
7748       : HTemplateInstruction<2>(HType::HeapObject()) {
7749     SetOperandAt(0, value);
7750     SetOperandAt(1, map);
7751     set_representation(Representation::Tagged());
7752     SetFlag(kUseGVN);
7753     SetDependsOnFlag(kMaps);
7754     SetDependsOnFlag(kElementsKind);
7755   }
7756 };
7757
7758
7759 class HForInPrepareMap V8_FINAL : public HTemplateInstruction<2> {
7760  public:
7761   DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*);
7762
7763   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7764     return Representation::Tagged();
7765   }
7766
7767   HValue* context() const { return OperandAt(0); }
7768   HValue* enumerable() const { return OperandAt(1); }
7769
7770   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
7771
7772   virtual HType CalculateInferredType() V8_OVERRIDE {
7773     return HType::Tagged();
7774   }
7775
7776   DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
7777
7778  private:
7779   HForInPrepareMap(HValue* context,
7780                    HValue* object) {
7781     SetOperandAt(0, context);
7782     SetOperandAt(1, object);
7783     set_representation(Representation::Tagged());
7784     SetAllSideEffects();
7785   }
7786 };
7787
7788
7789 class HForInCacheArray V8_FINAL : public HTemplateInstruction<2> {
7790  public:
7791   DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int);
7792
7793   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7794     return Representation::Tagged();
7795   }
7796
7797   HValue* enumerable() const { return OperandAt(0); }
7798   HValue* map() const { return OperandAt(1); }
7799   int idx() const { return idx_; }
7800
7801   HForInCacheArray* index_cache() {
7802     return index_cache_;
7803   }
7804
7805   void set_index_cache(HForInCacheArray* index_cache) {
7806     index_cache_ = index_cache;
7807   }
7808
7809   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
7810
7811   virtual HType CalculateInferredType() V8_OVERRIDE {
7812     return HType::Tagged();
7813   }
7814
7815   DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
7816
7817  private:
7818   HForInCacheArray(HValue* enumerable,
7819                    HValue* keys,
7820                    int idx) : idx_(idx) {
7821     SetOperandAt(0, enumerable);
7822     SetOperandAt(1, keys);
7823     set_representation(Representation::Tagged());
7824   }
7825
7826   int idx_;
7827   HForInCacheArray* index_cache_;
7828 };
7829
7830
7831 class HLoadFieldByIndex V8_FINAL : public HTemplateInstruction<2> {
7832  public:
7833   DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*);
7834
7835   HLoadFieldByIndex(HValue* object,
7836                     HValue* index) {
7837     SetOperandAt(0, object);
7838     SetOperandAt(1, index);
7839     SetChangesFlag(kNewSpacePromotion);
7840     set_representation(Representation::Tagged());
7841   }
7842
7843   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7844     if (index == 1) {
7845       return Representation::Smi();
7846     } else {
7847       return Representation::Tagged();
7848     }
7849   }
7850
7851   HValue* object() const { return OperandAt(0); }
7852   HValue* index() const { return OperandAt(1); }
7853
7854   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;  // NOLINT
7855
7856   virtual HType CalculateInferredType() V8_OVERRIDE {
7857     return HType::Tagged();
7858   }
7859
7860   DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
7861
7862  private:
7863   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7864 };
7865
7866
7867 class HStoreFrameContext: public HUnaryOperation {
7868  public:
7869   DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*);
7870
7871   HValue* context() { return OperandAt(0); }
7872
7873   virtual Representation RequiredInputRepresentation(int index) {
7874     return Representation::Tagged();
7875   }
7876
7877   DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext)
7878  private:
7879   explicit HStoreFrameContext(HValue* context)
7880       : HUnaryOperation(context) {
7881     set_representation(Representation::Tagged());
7882     SetChangesFlag(kContextSlots);
7883   }
7884 };
7885
7886
7887 class HAllocateBlockContext: public HTemplateInstruction<2> {
7888  public:
7889   DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*,
7890                                  HValue*, Handle<ScopeInfo>);
7891   HValue* context() const { return OperandAt(0); }
7892   HValue* function() const { return OperandAt(1); }
7893   Handle<ScopeInfo> scope_info() const { return scope_info_; }
7894
7895   virtual Representation RequiredInputRepresentation(int index) {
7896     return Representation::Tagged();
7897   }
7898
7899   virtual OStream& PrintDataTo(OStream& os) const;  // NOLINT
7900
7901   DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext)
7902
7903  private:
7904   HAllocateBlockContext(HValue* context,
7905                         HValue* function,
7906                         Handle<ScopeInfo> scope_info)
7907       : scope_info_(scope_info) {
7908     SetOperandAt(0, context);
7909     SetOperandAt(1, function);
7910     set_representation(Representation::Tagged());
7911   }
7912
7913   Handle<ScopeInfo> scope_info_;
7914 };
7915
7916
7917 class HNullarySIMDOperation V8_FINAL : public HTemplateInstruction<1> {
7918  public:
7919   static HInstruction* New(Zone* zone,
7920                            HValue* context,
7921                            BuiltinFunctionId op);
7922
7923   HValue* context() { return OperandAt(0); }
7924
7925   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;
7926
7927   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7928     return Representation::Tagged();
7929   }
7930
7931   BuiltinFunctionId op() const { return op_; }
7932   const char* OpName() const;
7933
7934   DECLARE_CONCRETE_INSTRUCTION(NullarySIMDOperation)
7935
7936  protected:
7937   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
7938     HNullarySIMDOperation* b = HNullarySIMDOperation::cast(other);
7939     return op_ == b->op();
7940   }
7941
7942  private:
7943   HNullarySIMDOperation(HValue* context, BuiltinFunctionId op)
7944       : HTemplateInstruction<1>(HType::None()), op_(op) {
7945     SetOperandAt(0, context);
7946     switch (op) {
7947 #define SIMD_NULLARY_OPERATION_CASE_ITEM(p1, p2, name, representation)    \
7948       case k##name:                                                       \
7949         set_representation(Representation::representation());             \
7950         set_type(HType::FromRepresentation(representation_));         \
7951         break;
7952 SIMD_NULLARY_OPERATIONS(SIMD_NULLARY_OPERATION_CASE_ITEM)
7953 #undef SIMD_NULLARY_OPERATION_CASE_ITEM
7954       default:
7955         UNREACHABLE();
7956     }
7957     SetFlag(kUseGVN);
7958   }
7959
7960   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
7961
7962   BuiltinFunctionId op_;
7963 };
7964
7965
7966 class HUnarySIMDOperation V8_FINAL : public HTemplateInstruction<2> {
7967  public:
7968   static HInstruction* New(Zone* zone,
7969                            HValue* context,
7970                            HValue* value,
7971                            BuiltinFunctionId op,
7972                            Representation to = Representation::Float32x4());
7973
7974   HValue* context() { return OperandAt(0); }
7975   HValue* value() const { return OperandAt(1); }
7976
7977   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;
7978
7979   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
7980     if (index == 0) {
7981       return Representation::Tagged();
7982     } else if (op_ == kSIMD128Change) {
7983       return value()->representation();
7984     } else {
7985       switch (op_) {
7986 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, representation)    \
7987         case k##name:                                                       \
7988           return Representation::representation();
7989 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
7990 SIMD_UNARY_OPERATIONS_FOR_PROPERTY_ACCESS(SIMD_UNARY_OPERATION_CASE_ITEM)
7991 #undef SIMD_UNARY_OPERATION_CASE_ITEM
7992         default:
7993           UNREACHABLE();
7994           return Representation::None();
7995       }
7996     }
7997   }
7998
7999   BuiltinFunctionId op() const { return op_; }
8000   const char* OpName() const;
8001
8002   DECLARE_CONCRETE_INSTRUCTION(UnarySIMDOperation)
8003
8004  protected:
8005   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
8006     HUnarySIMDOperation* b = HUnarySIMDOperation::cast(other);
8007     return op_ == b->op();
8008   }
8009
8010  private:
8011   HUnarySIMDOperation(HValue* context, HValue* value, BuiltinFunctionId op,
8012                       Representation to = Representation::Float32x4())
8013       : HTemplateInstruction<2>(HType::None()), op_(op) {
8014     SetOperandAt(0, context);
8015     SetOperandAt(1, value);
8016     switch (op) {
8017       case kSIMD128Change:
8018         set_representation(to);
8019         set_type(HType::FromRepresentation(to));
8020         break;
8021 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5)  \
8022       case k##name:                                                       \
8023         set_representation(Representation::representation());             \
8024         set_type(HType::FromRepresentation(representation_));         \
8025         if (Representation::p5().IsInteger32())  {                        \
8026           SetFlag(kTruncatingToInt32);                                    \
8027         }                                                                 \
8028         break;
8029 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
8030 SIMD_UNARY_OPERATIONS_FOR_PROPERTY_ACCESS(SIMD_UNARY_OPERATION_CASE_ITEM)
8031 #undef SIMD_UNARY_OPERATION_CASE_ITEM
8032       default:
8033         UNREACHABLE();
8034     }
8035     SetFlag(kUseGVN);
8036   }
8037
8038   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
8039
8040   BuiltinFunctionId op_;
8041 };
8042
8043
8044 class HBinarySIMDOperation V8_FINAL : public HTemplateInstruction<3> {
8045  public:
8046   static HInstruction* New(Zone* zone,
8047                            HValue* context,
8048                            HValue* left,
8049                            HValue* right,
8050                            BuiltinFunctionId op);
8051
8052   HValue* context() { return OperandAt(0); }
8053   HValue* left() const { return OperandAt(1); }
8054   HValue* right() const { return OperandAt(2); }
8055
8056   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;
8057
8058   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
8059     if (index == 0) {
8060       return Representation::Tagged();
8061     } else {
8062       switch (op_) {
8063 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, p4, left_representation, \
8064                                         right_representation)                  \
8065       case k##name:                                                            \
8066         return index == 1 ? Representation::left_representation()              \
8067                           : Representation::right_representation();            \
8068         break;
8069 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
8070 #undef SIMD_BINARY_OPERATION_CASE_ITEM
8071         default:
8072           UNREACHABLE();
8073           return Representation::None();
8074       }
8075     }
8076   }
8077
8078   BuiltinFunctionId op() const { return op_; }
8079   const char* OpName() const;
8080
8081   DECLARE_CONCRETE_INSTRUCTION(BinarySIMDOperation)
8082
8083  protected:
8084   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
8085     HBinarySIMDOperation* b = HBinarySIMDOperation::cast(other);
8086     return op_ == b->op();
8087   }
8088
8089  private:
8090   HBinarySIMDOperation(HValue* context, HValue* left, HValue* right,
8091                        BuiltinFunctionId op)
8092       : HTemplateInstruction<3>(HType::None()), op_(op) {
8093     SetOperandAt(0, context);
8094     SetOperandAt(1, left);
8095     SetOperandAt(2, right);
8096     switch (op) {
8097 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, p6)  \
8098       case k##name:                                                            \
8099         set_representation(Representation::representation());                  \
8100         set_type(HType::FromRepresentation(representation_));              \
8101         if (Representation::p5().IsInteger32() ||                              \
8102             Representation::p6().IsInteger32())  {                             \
8103           SetFlag(kTruncatingToInt32);                                         \
8104         }                                                                      \
8105         break;
8106 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
8107 #undef SIMD_BINARY_OPERATION_CASE_ITEM
8108       default:
8109         UNREACHABLE();
8110     }
8111     SetFlag(kUseGVN);
8112   }
8113
8114   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
8115
8116   BuiltinFunctionId op_;
8117 };
8118
8119
8120 class HTernarySIMDOperation V8_FINAL : public HTemplateInstruction<4> {
8121  public:
8122   static HInstruction* New(Zone* zone,
8123                            HValue* context,
8124                            HValue* first,
8125                            HValue* second,
8126                            HValue* third,
8127                            BuiltinFunctionId op);
8128
8129   HValue* context() { return OperandAt(0); }
8130   HValue* first() const { return OperandAt(1); }
8131   HValue* second() const { return OperandAt(2); }
8132   HValue* third() const { return OperandAt(3); }
8133
8134   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;
8135
8136   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
8137     if (index == 0) {
8138       return Representation::Tagged();
8139     } else {
8140       switch (op_) {
8141 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4,                     \
8142             first_representation, second_representation, third_representation) \
8143         case k##name:                                                          \
8144           switch (index) {                                                     \
8145             case 1: return Representation::first_representation();             \
8146             case 2: return Representation::second_representation();            \
8147             case 3: return Representation::third_representation();             \
8148             default:                                                           \
8149               UNREACHABLE();                                                   \
8150               return Representation::None();                                   \
8151           }
8152 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
8153 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
8154         default:
8155           UNREACHABLE();
8156           return Representation::None();
8157       }
8158     }
8159   }
8160
8161   BuiltinFunctionId op() const { return op_; }
8162   const char* OpName() const;
8163
8164   DECLARE_CONCRETE_INSTRUCTION(TernarySIMDOperation)
8165
8166  protected:
8167   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
8168     HTernarySIMDOperation* b = HTernarySIMDOperation::cast(other);
8169     return op_ == b->op();
8170   }
8171
8172  private:
8173   HTernarySIMDOperation(HValue* context, HValue* first, HValue* second,
8174                         HValue* third, BuiltinFunctionId op)
8175       : HTemplateInstruction<4>(HType::None()), op_(op) {
8176     SetOperandAt(0, context);
8177     SetOperandAt(1, first);
8178     SetOperandAt(2, second);
8179     SetOperandAt(3, third);
8180     switch (op) {
8181 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5,     \
8182                                          p6, p7)                               \
8183       case k##name:                                                            \
8184         set_representation(Representation::representation());                  \
8185         set_type(HType::FromRepresentation(representation_));              \
8186         if (Representation::p5().IsInteger32() ||                              \
8187             Representation::p6().IsInteger32() ||                              \
8188             Representation::p7().IsInteger32())  {                             \
8189           SetFlag(kTruncatingToInt32);                                         \
8190         }                                                                      \
8191         break;
8192 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
8193 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
8194       default:
8195         UNREACHABLE();
8196     }
8197     SetFlag(kUseGVN);
8198   }
8199
8200   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
8201
8202   BuiltinFunctionId op_;
8203 };
8204
8205
8206 class HQuarternarySIMDOperation V8_FINAL : public HTemplateInstruction<5> {
8207  public:
8208   static HInstruction* New(Zone* zone,
8209                            HValue* context,
8210                            HValue* x,
8211                            HValue* y,
8212                            HValue* z,
8213                            HValue* w,
8214                            BuiltinFunctionId op);
8215
8216   HValue* context() { return OperandAt(0); }
8217   HValue* x() const { return OperandAt(1); }
8218   HValue* y() const { return OperandAt(2); }
8219   HValue* z() const { return OperandAt(3); }
8220   HValue* w() const { return OperandAt(4); }
8221
8222   virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE;
8223
8224   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
8225     if (index == 0) {
8226       return Representation::Tagged();
8227     } else {
8228       switch (op_) {
8229 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4,                 \
8230             first_representation, second_representation, third_representation, \
8231             fourth_representation)                                             \
8232         case k##name:                                                          \
8233           switch (index) {                                                     \
8234             case 1: return Representation::first_representation();             \
8235             case 2: return Representation::second_representation();            \
8236             case 3: return Representation::third_representation();             \
8237             case 4: return Representation::fourth_representation();            \
8238             default:                                                           \
8239               UNREACHABLE();                                                   \
8240               return Representation::None();                                   \
8241           }
8242 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
8243 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
8244         default:
8245           UNREACHABLE();
8246           return Representation::None();
8247       }
8248     }
8249   }
8250
8251   BuiltinFunctionId op() const { return op_; }
8252   const char* OpName() const;
8253
8254   DECLARE_CONCRETE_INSTRUCTION(QuarternarySIMDOperation)
8255
8256  protected:
8257   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
8258     HQuarternarySIMDOperation* b = HQuarternarySIMDOperation::cast(other);
8259     return op_ == b->op();
8260   }
8261
8262  private:
8263   HQuarternarySIMDOperation(HValue* context, HValue* x, HValue* y, HValue* z,
8264                             HValue* w, BuiltinFunctionId op)
8265       : HTemplateInstruction<5>(HType::None()), op_(op) {
8266     SetOperandAt(0, context);
8267     SetOperandAt(1, x);
8268     SetOperandAt(2, y);
8269     SetOperandAt(3, z);
8270     SetOperandAt(4, w);
8271     switch (op) {
8272 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, representation, p5, \
8273                                              p6, p7, p8)                       \
8274       case k##name:                                                            \
8275         set_representation(Representation::representation());                  \
8276         set_type(HType::FromRepresentation(representation_));              \
8277         if (Representation::p5().IsInteger32() ||                              \
8278             Representation::p6().IsInteger32() ||                              \
8279             Representation::p7().IsInteger32() ||                              \
8280             Representation::p8().IsInteger32())  {                             \
8281           SetFlag(kTruncatingToInt32);                                         \
8282         }                                                                      \
8283         break;
8284 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
8285 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
8286       default:
8287         UNREACHABLE();
8288     }
8289     SetFlag(kUseGVN);
8290   }
8291
8292   virtual bool IsDeletable() const V8_OVERRIDE { return true; }
8293
8294   BuiltinFunctionId op_;
8295 };
8296
8297
8298 #undef DECLARE_INSTRUCTION
8299 #undef DECLARE_CONCRETE_INSTRUCTION
8300
8301 } }  // namespace v8::internal
8302
8303 #endif  // V8_HYDROGEN_INSTRUCTIONS_H_