Version 3.0.0.

Improved performance by (partially) addressing issue 957 on IA-32. Still needs more work for the other architectures.


git-svn-id: http://v8.googlecode.com/svn/trunk@5932 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
new file mode 100644
index 0000000..ff1ab1a
--- /dev/null
+++ b/src/hydrogen-instructions.h
@@ -0,0 +1,2885 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HYDROGEN_INSTRUCTIONS_H_
+#define V8_HYDROGEN_INSTRUCTIONS_H_
+
+#include "v8.h"
+#include "code-stubs.h"
+#include "string-stream.h"
+#include "zone.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class HBasicBlock;
+class HEnvironment;
+class HInstruction;
+class HLoopInformation;
+class HValue;
+class LInstruction;
+class LChunkBuilder;
+
+
+// Type hierarchy:
+//
+// HValue
+//   HInstruction
+//     HAccessArgumentsAt
+//     HApplyArguments
+//     HArgumentsElements
+//     HArgumentsLength
+//     HArgumentsObject
+//     HBinaryOperation
+//       HArithmeticBinaryOperation
+//         HAdd
+//         HDiv
+//         HMod
+//         HMul
+//         HSub
+//       HBitwiseBinaryOperation
+//         HBitAnd
+//         HBitOr
+//         HBitXor
+//         HSar
+//         HShl
+//         HShr
+//       HBoundsCheck
+//       HCompare
+//       HCompareJSObjectEq
+//       HInstanceOf
+//       HLoadKeyed
+//         HLoadKeyedFastElement
+//         HLoadKeyedGeneric
+//       HLoadNamedGeneric
+//       HStoreNamed
+//         HStoreNamedField
+//         HStoreNamedGeneric
+//     HBlockEntry
+//     HCall
+//       HCallConstantFunction
+//       HCallFunction
+//       HCallGlobal
+//       HCallKeyed
+//       HCallKnownGlobal
+//       HCallNamed
+//       HCallNew
+//       HCallRuntime
+//     HCallStub
+//     HConstant
+//     HControlInstruction
+//       HGoto
+//       HUnaryControlInstruction
+//         HBranch
+//         HCompareMapAndBranch
+//         HReturn
+//         HThrow
+//     HDeoptimize
+//     HEnterInlined
+//     HFunctionLiteral
+//     HGlobalObject
+//     HGlobalReceiver
+//     HLeaveInlined
+//     HLoadGlobal
+//     HMaterializedLiteral
+//       HArrayLiteral
+//       HObjectLiteral
+//       HRegExpLiteral
+//     HOsrEntry
+//     HParameter
+//     HSimulate
+//     HStackCheck
+//     HStoreKeyed
+//       HStoreKeyedFastElement
+//       HStoreKeyedGeneric
+//     HUnaryOperation
+//       HArrayLength
+//       HBitNot
+//       HChange
+//       HCheckFunction
+//       HCheckInstanceType
+//       HCheckMap
+//       HCheckNonSmi
+//       HCheckPrototypeMaps
+//       HCheckSmi
+//       HDeleteProperty
+//       HLoadElements
+//         HTypeofIs
+//       HLoadNamedField
+//       HPushArgument
+//       HTypeof
+//       HUnaryMathOperation
+//       HUnaryPredicate
+//         HClassOfTest
+//         HHasCachedArrayIndex
+//         HHasInstanceType
+//         HIsNull
+//         HIsSmi
+//       HValueOf
+//     HUnknownOSRValue
+//   HPhi
+
+#define HYDROGEN_ALL_INSTRUCTION_LIST(V)       \
+  V(ArithmeticBinaryOperation)                 \
+  V(BinaryOperation)                           \
+  V(BitwiseBinaryOperation)                    \
+  V(Call)                                      \
+  V(ControlInstruction)                        \
+  V(Instruction)                               \
+  V(LoadKeyed)                                 \
+  V(MaterializedLiteral)                       \
+  V(Phi)                                       \
+  V(StoreKeyed)                                \
+  V(StoreNamed)                                \
+  V(UnaryControlInstruction)                   \
+  V(UnaryOperation)                            \
+  HYDROGEN_CONCRETE_INSTRUCTION_LIST(V)
+
+
+#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V)  \
+  V(AccessArgumentsAt)                         \
+  V(Add)                                       \
+  V(ApplyArguments)                            \
+  V(ArgumentsElements)                         \
+  V(ArgumentsLength)                           \
+  V(ArgumentsObject)                           \
+  V(ArrayLength)                               \
+  V(ArrayLiteral)                              \
+  V(BitAnd)                                    \
+  V(BitNot)                                    \
+  V(BitOr)                                     \
+  V(BitXor)                                    \
+  V(BlockEntry)                                \
+  V(BoundsCheck)                               \
+  V(Branch)                                    \
+  V(CallConstantFunction)                      \
+  V(CallFunction)                              \
+  V(CallGlobal)                                \
+  V(CallKeyed)                                 \
+  V(CallKnownGlobal)                           \
+  V(CallNamed)                                 \
+  V(CallNew)                                   \
+  V(CallRuntime)                               \
+  V(CallStub)                                  \
+  V(Change)                                    \
+  V(CheckFunction)                             \
+  V(CheckInstanceType)                         \
+  V(CheckMap)                                  \
+  V(CheckNonSmi)                               \
+  V(CheckPrototypeMaps)                        \
+  V(CheckSmi)                                  \
+  V(Compare)                                   \
+  V(CompareJSObjectEq)                         \
+  V(CompareMapAndBranch)                       \
+  V(Constant)                                  \
+  V(DeleteProperty)                            \
+  V(Deoptimize)                                \
+  V(Div)                                       \
+  V(EnterInlined)                              \
+  V(FunctionLiteral)                           \
+  V(GlobalObject)                              \
+  V(GlobalReceiver)                            \
+  V(Goto)                                      \
+  V(InstanceOf)                                \
+  V(IsNull)                                    \
+  V(IsSmi)                                     \
+  V(HasInstanceType)                           \
+  V(HasCachedArrayIndex)                       \
+  V(ClassOfTest)                               \
+  V(LeaveInlined)                              \
+  V(LoadElements)                              \
+  V(LoadGlobal)                                \
+  V(LoadKeyedFastElement)                      \
+  V(LoadKeyedGeneric)                          \
+  V(LoadNamedField)                            \
+  V(LoadNamedGeneric)                          \
+  V(Mod)                                       \
+  V(Mul)                                       \
+  V(ObjectLiteral)                             \
+  V(OsrEntry)                                  \
+  V(Parameter)                                 \
+  V(PushArgument)                              \
+  V(RegExpLiteral)                             \
+  V(Return)                                    \
+  V(Sar)                                       \
+  V(Shl)                                       \
+  V(Shr)                                       \
+  V(Simulate)                                  \
+  V(StackCheck)                                \
+  V(StoreGlobal)                               \
+  V(StoreKeyedFastElement)                     \
+  V(StoreKeyedGeneric)                         \
+  V(StoreNamedField)                           \
+  V(StoreNamedGeneric)                         \
+  V(Sub)                                       \
+  V(Throw)                                     \
+  V(Typeof)                                    \
+  V(TypeofIs)                                  \
+  V(UnaryMathOperation)                        \
+  V(UnknownOSRValue)                           \
+  V(ValueOf)
+
+#define GVN_FLAG_LIST(V)                       \
+  V(Calls)                                     \
+  V(InobjectFields)                            \
+  V(BackingStoreFields)                        \
+  V(ArrayElements)                             \
+  V(GlobalVars)                                \
+  V(Maps)                                      \
+  V(ArrayLengths)                              \
+  V(OsrEntries)
+
+#define DECLARE_INSTRUCTION(type)                   \
+  virtual bool Is##type() const { return true; }    \
+  static H##type* cast(HValue* value) {             \
+    ASSERT(value->Is##type());                      \
+    return reinterpret_cast<H##type*>(value);       \
+  }                                                 \
+  Opcode opcode() const { return HValue::k##type; }
+
+
+#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)              \
+  virtual LInstruction* CompileToLithium(LChunkBuilder* builder); \
+  virtual const char* Mnemonic() const { return mnemonic; }       \
+  DECLARE_INSTRUCTION(type)
+
+
+
+template<int kSize>
+class HOperandVector : public EmbeddedVector<HValue*, kSize> {
+ public:
+  HOperandVector() : EmbeddedVector<HValue*, kSize>(NULL) { }
+};
+
+
+class Range: public ZoneObject {
+ public:
+  Range() : lower_(kMinInt),
+            upper_(kMaxInt),
+            next_(NULL),
+            can_be_minus_zero_(false) { }
+
+  Range(int32_t lower, int32_t upper)
+      : lower_(lower), upper_(upper), next_(NULL), can_be_minus_zero_(false) { }
+
+  bool IsInSmiRange() const {
+    return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
+  }
+  void KeepOrder();
+  void Verify() const;
+  int32_t upper() const { return upper_; }
+  int32_t lower() const { return lower_; }
+  Range* next() const { return next_; }
+  Range* CopyClearLower() const { return new Range(kMinInt, upper_); }
+  Range* CopyClearUpper() const { return new Range(lower_, kMaxInt); }
+  void ClearLower() { lower_ = kMinInt; }
+  void ClearUpper() { upper_ = kMaxInt; }
+  Range* Copy() const { return new Range(lower_, upper_); }
+  bool IsMostGeneric() const { return lower_ == kMinInt && upper_ == kMaxInt; }
+  int32_t Mask() const;
+  void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
+  bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
+  bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
+  bool CanBeNegative() const { return lower_ < 0; }
+  bool Includes(int value) const {
+    return lower_ <= value && upper_ >= value;
+  }
+
+  void Sar(int32_t value) {
+    int32_t bits = value & 0x1F;
+    lower_ = lower_ >> bits;
+    upper_ = upper_ >> bits;
+    set_can_be_minus_zero(false);
+  }
+
+  void Shl(int32_t value) {
+    int32_t bits = value & 0x1F;
+    int old_lower = lower_;
+    int old_upper = upper_;
+    lower_ = lower_ << bits;
+    upper_ = upper_ << bits;
+    if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) {
+      upper_ = kMaxInt;
+      lower_ = kMinInt;
+    }
+    set_can_be_minus_zero(false);
+  }
+
+  void StackUpon(Range* other) {
+    Intersect(other);
+    next_ = other;
+  }
+
+  void Intersect(Range* other) {
+    upper_ = Min(upper_, other->upper_);
+    lower_ = Max(lower_, other->lower_);
+    bool b = CanBeMinusZero() && other->CanBeMinusZero();
+    set_can_be_minus_zero(b);
+  }
+
+  void Union(Range* other) {
+    upper_ = Max(upper_, other->upper_);
+    lower_ = Min(lower_, other->lower_);
+    bool b = CanBeMinusZero() || other->CanBeMinusZero();
+    set_can_be_minus_zero(b);
+  }
+
+  void Add(int32_t value);
+  bool AddAndCheckOverflow(Range* other);
+  bool SubAndCheckOverflow(Range* other);
+  bool MulAndCheckOverflow(Range* other);
+
+ private:
+  int32_t lower_;
+  int32_t upper_;
+  Range* next_;
+  bool can_be_minus_zero_;
+};
+
+
+class Representation {
+ public:
+  enum Kind {
+    kNone,
+    kTagged,
+    kDouble,
+    kInteger32,
+    kNumRepresentations
+  };
+
+  Representation() : kind_(kNone) { }
+
+  static Representation None() { return Representation(kNone); }
+  static Representation Tagged() { return Representation(kTagged); }
+  static Representation Integer32() { return Representation(kInteger32); }
+  static Representation Double() { return Representation(kDouble); }
+
+  bool Equals(const Representation& other) const {
+    return kind_ == other.kind_;
+  }
+
+  Kind kind() const { return kind_; }
+  bool IsNone() const { return kind_ == kNone; }
+  bool IsTagged() const { return kind_ == kTagged; }
+  bool IsInteger32() const { return kind_ == kInteger32; }
+  bool IsDouble() const { return kind_ == kDouble; }
+  bool IsSpecialization() const {
+    return kind_ == kInteger32 || kind_ == kDouble;
+  }
+  const char* Mnemonic() const;
+
+ private:
+  explicit Representation(Kind k) : kind_(k) { }
+
+  Kind kind_;
+};
+
+
+class HType {
+ public:
+  HType() : type_(kUninitialized) { }
+
+  static HType Tagged() { return HType(kTagged); }
+  static HType TaggedPrimitive() { return HType(kTaggedPrimitive); }
+  static HType TaggedNumber() { return HType(kTaggedNumber); }
+  static HType Smi() { return HType(kSmi); }
+  static HType HeapNumber() { return HType(kHeapNumber); }
+  static HType String() { return HType(kString); }
+  static HType Boolean() { return HType(kBoolean); }
+  static HType NonPrimitive() { return HType(kNonPrimitive); }
+  static HType JSArray() { return HType(kJSArray); }
+  static HType JSObject() { return HType(kJSObject); }
+  static HType Uninitialized() { return HType(kUninitialized); }
+
+  // Return the weakest (least precise) common type.
+  HType Combine(HType other) {
+    return HType(static_cast<Type>(type_ & other.type_));
+  }
+
+  bool Equals(const HType& other) {
+    return type_ == other.type_;
+  }
+
+  bool IsSubtypeOf(const HType& other) {
+    return Combine(other).Equals(other);
+  }
+
+  bool IsTagged() {
+    ASSERT(type_ != kUninitialized);
+    return ((type_ & kTagged) == kTagged);
+  }
+
+  bool IsTaggedPrimitive() {
+    ASSERT(type_ != kUninitialized);
+    return ((type_ & kTaggedPrimitive) == kTaggedPrimitive);
+  }
+
+  bool IsTaggedNumber() {
+    ASSERT(type_ != kUninitialized);
+    return ((type_ & kTaggedNumber) == kTaggedNumber);
+  }
+
+  bool IsSmi() {
+    ASSERT(type_ != kUninitialized);
+    return ((type_ & kSmi) == kSmi);
+  }
+
+  bool IsHeapNumber() {
+    ASSERT(type_ != kUninitialized);
+    return ((type_ & kHeapNumber) == kHeapNumber);
+  }
+
+  bool IsString() {
+    ASSERT(type_ != kUninitialized);
+    return ((type_ & kString) == kString);
+  }
+
+  bool IsBoolean() {
+    ASSERT(type_ != kUninitialized);
+    return ((type_ & kBoolean) == kBoolean);
+  }
+
+  bool IsNonPrimitive() {
+    ASSERT(type_ != kUninitialized);
+    return ((type_ & kNonPrimitive) == kNonPrimitive);
+  }
+
+  bool IsJSArray() {
+    ASSERT(type_ != kUninitialized);
+    return ((type_ & kJSArray) == kJSArray);
+  }
+
+  bool IsJSObject() {
+    ASSERT(type_ != kUninitialized);
+    return ((type_ & kJSObject) == kJSObject);
+  }
+
+  bool IsUninitialized() {
+    return type_ == kUninitialized;
+  }
+
+  static HType TypeFromValue(Handle<Object> value);
+
+  const char* ToString();
+  const char* ToShortString();
+
+ private:
+  enum Type {
+    kTagged = 0x1,           // 0000 0000 0000 0001
+    kTaggedPrimitive = 0x5,  // 0000 0000 0000 0101
+    kTaggedNumber = 0xd,     // 0000 0000 0000 1101
+    kSmi = 0x1d,             // 0000 0000 0001 1101
+    kHeapNumber = 0x2d,      // 0000 0000 0010 1101
+    kString = 0x45,          // 0000 0000 0100 0101
+    kBoolean = 0x85,         // 0000 0000 1000 0101
+    kNonPrimitive = 0x101,   // 0000 0001 0000 0001
+    kJSObject = 0x301,       // 0000 0011 0000 0001
+    kJSArray = 0x701,        // 0000 0111 1000 0001
+    kUninitialized = 0x1fff  // 0001 1111 1111 1111
+  };
+
+  explicit HType(Type t) : type_(t) { }
+
+  Type type_;
+};
+
+
+class HValue: public ZoneObject {
+ public:
+  static const int kNoNumber = -1;
+
+  // There must be one corresponding kDepends flag for every kChanges flag and
+  // the order of the kChanges flags must be exactly the same as of the kDepends
+  // flags.
+  enum Flag {
+    // Declare global value numbering flags.
+  #define DECLARE_DO(type) kChanges##type, kDependsOn##type,
+    GVN_FLAG_LIST(DECLARE_DO)
+  #undef DECLARE_DO
+    kFlexibleRepresentation,
+    kUseGVN,
+    kCanOverflow,
+    kBailoutOnMinusZero,
+    kCanBeDivByZero,
+    kIsArguments,
+    kTruncatingToInt32,
+    kLastFlag = kTruncatingToInt32
+  };
+
+  STATIC_ASSERT(kLastFlag < kBitsPerInt);
+
+  static const int kChangesToDependsFlagsLeftShift = 1;
+
+  static int ChangesFlagsMask() {
+    int result = 0;
+    // Create changes mask.
+#define DECLARE_DO(type) result |= (1 << kChanges##type);
+  GVN_FLAG_LIST(DECLARE_DO)
+#undef DECLARE_DO
+    return result;
+  }
+
+  static int DependsFlagsMask() {
+    return ConvertChangesToDependsFlags(ChangesFlagsMask());
+  }
+
+  static int ConvertChangesToDependsFlags(int flags) {
+    return flags << kChangesToDependsFlagsLeftShift;
+  }
+
+  // A flag mask to mark an instruction as having arbitrary side effects.
+  static int AllSideEffects() {
+    return ChangesFlagsMask() & ~(1 << kChangesOsrEntries);
+  }
+
+  static HValue* cast(HValue* value) { return value; }
+
+  enum Opcode {
+    // Declare a unique enum value for each hydrogen instruction.
+  #define DECLARE_DO(type) k##type,
+    HYDROGEN_ALL_INSTRUCTION_LIST(DECLARE_DO)
+  #undef DECLARE_DO
+    kMaxInstructionClass
+  };
+
+  HValue() : block_(NULL),
+             id_(kNoNumber),
+             uses_(2),
+             type_(HType::Tagged()),
+             range_(NULL),
+             flags_(0) {}
+  virtual ~HValue() {}
+
+  HBasicBlock* block() const { return block_; }
+  void SetBlock(HBasicBlock* block);
+
+  int id() const { return id_; }
+  void set_id(int id) { id_ = id; }
+
+  const ZoneList<HValue*>* uses() const { return &uses_; }
+
+  virtual bool EmitAtUses() const { return false; }
+  Representation representation() const { return representation_; }
+  void ChangeRepresentation(Representation r) {
+    // Representation was already set and is allowed to be changed.
+    ASSERT(!representation_.IsNone());
+    ASSERT(!r.IsNone());
+    ASSERT(CheckFlag(kFlexibleRepresentation));
+    RepresentationChanged(r);
+    representation_ = r;
+  }
+
+  HType type() const { return type_; }
+  void set_type(HType type) {
+    ASSERT(uses_.length() == 0);
+    type_ = type;
+  }
+
+  // An operation needs to override this function iff:
+  //   1) it can produce an int32 output.
+  //   2) the true value of its output can potentially be minus zero.
+  // The implementation must set a flag so that it bails out in the case where
+  // it would otherwise output what should be a minus zero as an int32 zero.
+  // If the operation also exists in a form that takes int32 and outputs int32
+  // then the operation should return its input value so that we can propagate
+  // back.  There are two operations that need to propagate back to more than
+  // one input.  They are phi and binary add.  They always return NULL and
+  // expect the caller to take care of things.
+  virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited) {
+    visited->Add(id());
+    return NULL;
+  }
+
+  bool HasSideEffects() const {
+    return (flags_ & AllSideEffects()) != 0;
+  }
+  bool IsDefinedAfter(HBasicBlock* other) const;
+
+  // Operands.
+  virtual int OperandCount() const { return 0; }
+  virtual HValue* OperandAt(int index) const {
+    UNREACHABLE();
+    return NULL;
+  }
+  void SetOperandAt(int index, HValue* value);
+
+  int LookupOperandIndex(int occurrence_index, HValue* op) const;
+  bool UsesMultipleTimes(HValue* op) const;
+
+  void ReplaceAndDelete(HValue* other);
+  void ReplaceValue(HValue* other);
+  void ReplaceAtUse(HValue* use, HValue* other);
+  void ReplaceFirstAtUse(HValue* use, HValue* other, Representation r);
+  bool HasNoUses() const { return uses_.is_empty(); }
+  void ClearOperands();
+  void Delete();
+
+  int flags() const { return flags_; }
+  void SetFlagMask(int mask) { flags_ |= mask; }
+  void SetFlag(Flag f) { SetFlagMask(1 << f); }
+  void ClearFlagMask(int mask) { flags_ &= ~mask; }
+  void ClearFlag(Flag f) { ClearFlagMask(1 << f); }
+  bool CheckFlag(Flag f) const { return CheckFlagMask(1 << f); }
+  bool CheckFlagMask(int mask) const { return (flags_ & mask) != 0; }
+
+  Range* range() const { return range_; }
+  bool HasRange() const { return range_ != NULL; }
+  void AddNewRange(Range* r);
+  void RemoveLastAddedRange();
+  void ComputeInitialRange();
+
+  // Representation helpers.
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::None();
+  }
+  virtual Representation InferredRepresentation() const {
+    return representation();
+  }
+
+  // This gives the instruction an opportunity to replace itself with an
+  // instruction that does the same in some better way.  To replace an
+  // instruction with a new one, first add the new instruction to the graph,
+  // then return it.  Return NULL to have the instruction deleted.
+  virtual HValue* Canonicalize() { return this; }
+
+  // Declare virtual type testers.
+#define DECLARE_DO(type) virtual bool Is##type() const { return false; }
+  HYDROGEN_ALL_INSTRUCTION_LIST(DECLARE_DO)
+#undef DECLARE_DO
+
+  bool Equals(HValue* other) const;
+  virtual intptr_t Hashcode() const;
+
+  // Printing support.
+  virtual void PrintTo(StringStream* stream) const = 0;
+  void PrintNameTo(StringStream* stream);
+  static void PrintTypeTo(HType type, StringStream* stream);
+
+  virtual const char* Mnemonic() const = 0;
+  virtual Opcode opcode() const = 0;
+
+  // Updated the inferred type of this instruction and returns true if
+  // it has changed.
+  bool UpdateInferredType();
+
+  virtual HType CalculateInferredType() const;
+
+  // Helper for type conversions used by normal and phi instructions.
+  void InsertInputConversion(HInstruction* previous, int index, HType type);
+
+#ifdef DEBUG
+  virtual void Verify() const = 0;
+#endif
+
+ protected:
+  virtual bool DataEquals(HValue* other) const { return true; }
+  virtual void RepresentationChanged(Representation to) { }
+  virtual Range* InferRange();
+  virtual void DeleteFromGraph() = 0;
+  virtual void InternalSetOperandAt(int index, HValue* value) { UNREACHABLE(); }
+  void clear_block() {
+    ASSERT(block_ != NULL);
+    block_ = NULL;
+  }
+
+  void set_representation(Representation r) {
+    // Representation is set-once.
+    ASSERT(representation_.IsNone() && !r.IsNone());
+    representation_ = r;
+  }
+
+ private:
+  void InternalReplaceAtUse(HValue* use, HValue* other);
+  void RegisterUse(int index, HValue* new_value);
+
+  HBasicBlock* block_;
+
+  // The id of this instruction in the hydrogen graph, assigned when first
+  // added to the graph. Reflects creation order.
+  int id_;
+
+  Representation representation_;
+  ZoneList<HValue*> uses_;
+  HType type_;
+  Range* range_;
+  int flags_;
+
+  DISALLOW_COPY_AND_ASSIGN(HValue);
+};
+
+
+class HInstruction: public HValue {
+ public:
+  HInstruction* next() const { return next_; }
+  HInstruction* previous() const { return previous_; }
+
+  void PrintTo(StringStream* stream) const;
+  virtual void PrintDataTo(StringStream* stream) const {}
+
+  bool IsLinked() const { return block() != NULL; }
+  void Unlink();
+  void InsertBefore(HInstruction* next);
+  void InsertAfter(HInstruction* previous);
+
+  int position() const { return position_; }
+  bool has_position() const { return position_ != RelocInfo::kNoPosition; }
+  void set_position(int position) { position_ = position; }
+
+  virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
+
+#ifdef DEBUG
+  virtual void Verify() const;
+#endif
+
+  DECLARE_INSTRUCTION(Instruction)
+
+ protected:
+  HInstruction()
+      : next_(NULL),
+        previous_(NULL),
+        position_(RelocInfo::kNoPosition) {
+    SetFlag(kDependsOnOsrEntries);
+  }
+
+  virtual void DeleteFromGraph() { Unlink(); }
+
+ private:
+  void InitializeAsFirst(HBasicBlock* block) {
+    ASSERT(!IsLinked());
+    SetBlock(block);
+  }
+
+  HInstruction* next_;
+  HInstruction* previous_;
+  int position_;
+
+  friend class HBasicBlock;
+};
+
+
+class HBlockEntry: public HInstruction {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(BlockEntry, "block_entry")
+};
+
+
+class HControlInstruction: public HInstruction {
+ public:
+  virtual HBasicBlock* FirstSuccessor() const { return NULL; }
+  virtual HBasicBlock* SecondSuccessor() const { return NULL; }
+
+  DECLARE_INSTRUCTION(ControlInstruction)
+};
+
+
+class HDeoptimize: public HControlInstruction {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
+};
+
+
+class HGoto: public HControlInstruction {
+ public:
+  explicit HGoto(HBasicBlock* destination)
+      : destination_(destination),
+        include_stack_check_(false) {}
+
+  virtual HBasicBlock* FirstSuccessor() const { return destination_; }
+  void set_include_stack_check(bool include_stack_check) {
+    include_stack_check_ = include_stack_check;
+  }
+  bool include_stack_check() const { return include_stack_check_; }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
+
+ private:
+  HBasicBlock* destination_;
+  bool include_stack_check_;
+};
+
+
+class HUnaryControlInstruction: public HControlInstruction {
+ public:
+  explicit HUnaryControlInstruction(HValue* value) {
+    SetOperandAt(0, value);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  HValue* value() const { return OperandAt(0); }
+  virtual int OperandCount() const { return 1; }
+  virtual HValue* OperandAt(int index) const { return operands_[index]; }
+
+  DECLARE_INSTRUCTION(UnaryControlInstruction)
+
+ protected:
+  virtual void InternalSetOperandAt(int index, HValue* value) {
+    operands_[index] = value;
+  }
+
+ private:
+  HOperandVector<1> operands_;
+};
+
+
+class HBranch: public HUnaryControlInstruction {
+ public:
+  HBranch(HBasicBlock* true_destination,
+          HBasicBlock* false_destination,
+          HValue* boolean_value)
+      : HUnaryControlInstruction(boolean_value),
+        true_destination_(true_destination),
+        false_destination_(false_destination) {
+    ASSERT(true_destination != NULL && false_destination != NULL);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::None();
+  }
+
+  virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
+  virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
+
+ private:
+  HBasicBlock* true_destination_;
+  HBasicBlock* false_destination_;
+};
+
+
+class HCompareMapAndBranch: public HUnaryControlInstruction {
+ public:
+  HCompareMapAndBranch(HValue* result,
+                       Handle<Map> map,
+                       HBasicBlock* true_destination,
+                       HBasicBlock* false_destination)
+      : HUnaryControlInstruction(result),
+        map_(map),
+        true_destination_(true_destination),
+        false_destination_(false_destination) {
+    ASSERT(true_destination != NULL);
+    ASSERT(false_destination != NULL);
+    ASSERT(!map.is_null());
+  }
+
+  virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
+  virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
+
+  Handle<Map> map() const { return map_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareMapAndBranch, "compare_map_and_branch")
+
+ private:
+  Handle<Map> map_;
+  HBasicBlock* true_destination_;
+  HBasicBlock* false_destination_;
+};
+
+
+class HReturn: public HUnaryControlInstruction {
+ public:
+  explicit HReturn(HValue* result) : HUnaryControlInstruction(result) { }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(Return, "return")
+};
+
+
+class HThrow: public HUnaryControlInstruction {
+ public:
+  explicit HThrow(HValue* value) : HUnaryControlInstruction(value) { }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(Throw, "throw")
+};
+
+
+class HUnaryOperation: public HInstruction {
+ public:
+  explicit HUnaryOperation(HValue* value) {
+    SetOperandAt(0, value);
+  }
+
+  HValue* value() const { return OperandAt(0); }
+  virtual void PrintDataTo(StringStream* stream) const;
+  virtual int OperandCount() const { return 1; }
+  virtual HValue* OperandAt(int index) const { return operands_[index]; }
+
+  DECLARE_INSTRUCTION(UnaryOperation)
+
+ protected:
+  virtual void InternalSetOperandAt(int index, HValue* value) {
+    operands_[index] = value;
+  }
+
+ private:
+  HOperandVector<1> operands_;
+};
+
+
+class HChange: public HUnaryOperation {
+ public:
+  HChange(HValue* value,
+          Representation from,
+          Representation to)
+      : HUnaryOperation(value), from_(from), to_(to) {
+    ASSERT(!from.IsNone() && !to.IsNone());
+    ASSERT(!from.Equals(to));
+    set_representation(to);
+    SetFlag(kUseGVN);
+
+    if (from.IsInteger32() && to.IsTagged() && value->range() != NULL &&
+        value->range()->IsInSmiRange()) {
+      set_type(HType::Smi());
+    }
+  }
+
+  virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
+
+  Representation from() const { return from_; }
+  Representation to() const { return to_; }
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return from_;
+  }
+
+  bool CanTruncateToInt32() const {
+    for (int i = 0; i < uses()->length(); ++i) {
+      if (!uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) return false;
+    }
+    return true;
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(Change,
+                               CanTruncateToInt32() ? "truncate" : "change")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    if (!other->IsChange()) return false;
+    HChange* change = HChange::cast(other);
+    return value() == change->value()
+        && to().Equals(change->to())
+        && CanTruncateToInt32() == change->CanTruncateToInt32();
+  }
+
+ private:
+  Representation from_;
+  Representation to_;
+};
+
+
+class HSimulate: public HInstruction {
+ public:
+  HSimulate(int ast_id, int pop_count, int environment_height)
+      : ast_id_(ast_id),
+        pop_count_(pop_count),
+        environment_height_(environment_height),
+        values_(2),
+        assigned_indexes_(2) {}
+  virtual ~HSimulate() {}
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  bool HasAstId() const { return ast_id_ != AstNode::kNoNumber; }
+  int ast_id() const { return ast_id_; }
+  void set_ast_id(int id) {
+    ASSERT(!HasAstId());
+    ast_id_ = id;
+  }
+
+  int environment_height() const { return environment_height_; }
+  int pop_count() const { return pop_count_; }
+  const ZoneList<HValue*>* values() const { return &values_; }
+  int GetAssignedIndexAt(int index) const {
+    ASSERT(HasAssignedIndexAt(index));
+    return assigned_indexes_[index];
+  }
+  bool HasAssignedIndexAt(int index) const {
+    return assigned_indexes_[index] != kNoIndex;
+  }
+  void AddAssignedValue(int index, HValue* value) {
+    AddValue(index, value);
+  }
+  void AddPushedValue(HValue* value) {
+    AddValue(kNoIndex, value);
+  }
+  virtual int OperandCount() const { return values_.length(); }
+  virtual HValue* OperandAt(int index) const { return values_[index]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Simulate, "simulate")
+
+#ifdef DEBUG
+  virtual void Verify() const;
+#endif
+
+ protected:
+  virtual void InternalSetOperandAt(int index, HValue* value) {
+    values_[index] = value;
+  }
+
+ private:
+  static const int kNoIndex = -1;
+  void AddValue(int index, HValue* value) {
+    assigned_indexes_.Add(index);
+    // Resize the list of pushed values.
+    values_.Add(NULL);
+    // Set the operand through the base method in HValue to make sure that the
+    // use lists are correctly updated.
+    SetOperandAt(values_.length() - 1, value);
+  }
+  int ast_id_;
+  int pop_count_;
+  int environment_height_;
+  ZoneList<HValue*> values_;
+  ZoneList<int> assigned_indexes_;
+};
+
+
+class HStackCheck: public HInstruction {
+ public:
+  HStackCheck() { }
+
+  DECLARE_CONCRETE_INSTRUCTION(Throw, "stack_check")
+};
+
+
+class HEnterInlined: public HInstruction {
+ public:
+  HEnterInlined(Handle<JSFunction> closure, FunctionLiteral* function)
+      : closure_(closure), function_(function) {
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  Handle<JSFunction> closure() const { return closure_; }
+  FunctionLiteral* function() const { return function_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(EnterInlined, "enter_inlined")
+
+ private:
+  Handle<JSFunction> closure_;
+  FunctionLiteral* function_;
+};
+
+
+class HLeaveInlined: public HInstruction {
+ public:
+  HLeaveInlined() {}
+
+  DECLARE_CONCRETE_INSTRUCTION(LeaveInlined, "leave_inlined")
+};
+
+
+class HPushArgument: public HUnaryOperation {
+ public:
+  explicit HPushArgument(HValue* value)
+      : HUnaryOperation(value), argument_index_(-1) {
+    set_representation(Representation::Tagged());
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+  HValue* argument() const { return OperandAt(0); }
+  int argument_index() const { return argument_index_; }
+  void set_argument_index(int index) {
+    ASSERT(argument_index_ == -1 || index == argument_index_);
+    argument_index_ = index;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push_argument")
+
+ private:
+  int argument_index_;
+};
+
+
+class HGlobalObject: public HInstruction {
+ public:
+  HGlobalObject() {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+    SetFlag(kDependsOnCalls);
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global_object")
+};
+
+
+class HGlobalReceiver: public HInstruction {
+ public:
+  HGlobalReceiver() {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+    SetFlag(kDependsOnCalls);
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global_receiver")
+};
+
+
+class HCall: public HInstruction {
+ public:
+  // Construct a call with uninitialized arguments. The argument count
+  // includes the receiver.
+  explicit HCall(int count);
+
+  virtual HType CalculateInferredType() const { return HType::Tagged(); }
+
+  // TODO(3190496): This needs a cleanup. We don't want the arguments
+  // be operands of the call instruction. This results in bad code quality.
+  virtual int argument_count() const { return arguments_.length(); }
+  virtual int OperandCount() const { return argument_count(); }
+  virtual HValue* OperandAt(int index) const { return arguments_[index]; }
+  virtual HPushArgument* PushArgumentAt(int index) const {
+    return HPushArgument::cast(OperandAt(index));
+  }
+  virtual HValue* ArgumentAt(int index) const {
+    return PushArgumentAt(index)->argument();
+  }
+  virtual void SetArgumentAt(int index, HPushArgument* push_argument);
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_INSTRUCTION(Call)
+
+ protected:
+  virtual void InternalSetOperandAt(int index, HValue* value) {
+    arguments_[index] = value;
+  }
+
+  int argument_count_;
+  Vector<HValue*> arguments_;
+};
+
+
+class HCallConstantFunction: public HCall {
+ public:
+  HCallConstantFunction(Handle<JSFunction> function, int argument_count)
+      : HCall(argument_count), function_(function) { }
+
+  Handle<JSFunction> function() const { return function_; }
+  bool IsApplyFunction() const {
+    return function_->code() == Builtins::builtin(Builtins::FunctionApply);
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction, "call_constant_function")
+
+ private:
+  Handle<JSFunction> function_;
+};
+
+
+class HCallKeyed: public HCall {
+ public:
+  HCallKeyed(HValue* key, int argument_count)
+      : HCall(argument_count + 1) {
+    SetOperandAt(0, key);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  // TODO(3190496): This is a hack to get an additional operand that
+  // is not an argument to work with the current setup. This _needs_ a cleanup.
+  // (see HCall)
+  virtual void PrintDataTo(StringStream* stream) const;
+  HValue* key() const { return OperandAt(0); }
+  virtual int argument_count() const { return arguments_.length() - 1; }
+  virtual int OperandCount() const { return arguments_.length(); }
+  virtual HValue* OperandAt(int index) const { return arguments_[index]; }
+  virtual HPushArgument* PushArgumentAt(int index) const {
+    return HPushArgument::cast(OperandAt(index + 1));
+  }
+  virtual void SetArgumentAt(int index, HPushArgument* push_argument) {
+    HCall::SetArgumentAt(index + 1, push_argument);
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call_keyed")
+};
+
+
+class HCallNamed: public HCall {
+ public:
+  HCallNamed(Handle<String> name, int argument_count)
+      : HCall(argument_count), name_(name) { }
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  Handle<String> name() const { return name_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call_named")
+
+ private:
+  Handle<String> name_;
+};
+
+
+class HCallFunction: public HCall {
+ public:
+  explicit HCallFunction(int argument_count) : HCall(argument_count) { }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call_function")
+};
+
+
+class HCallGlobal: public HCall {
+ public:
+  HCallGlobal(Handle<String> name, int argument_count)
+      : HCall(argument_count), name_(name) { }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  Handle<String> name() const { return name_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call_global")
+
+ private:
+  Handle<String> name_;
+};
+
+
+class HCallKnownGlobal: public HCall {
+ public:
+  HCallKnownGlobal(Handle<JSFunction> target,
+                   int argument_count)
+      : HCall(argument_count), target_(target) { }
+
+  Handle<JSFunction> target() const { return target_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal, "call_known_global")
+
+ private:
+  Handle<JSFunction> target_;
+};
+
+
+class HCallNew: public HCall {
+ public:
+  explicit HCallNew(int argument_count) : HCall(argument_count) { }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  HValue* constructor() const { return ArgumentAt(0); }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallNew, "call_new")
+};
+
+
+class HCallRuntime: public HCall {
+ public:
+  HCallRuntime(Handle<String> name,
+               Runtime::Function* c_function,
+               int argument_count)
+      : HCall(argument_count), c_function_(c_function), name_(name) { }
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  Runtime::Function* function() const { return c_function_; }
+  Handle<String> name() const { return name_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call_runtime")
+
+ private:
+  Runtime::Function* c_function_;
+  Handle<String> name_;
+};
+
+
+class HArrayLength: public HUnaryOperation {
+ public:
+  explicit HArrayLength(HValue* value) : HUnaryOperation(value) {
+    // The length of an array is stored as a tagged value in the array
+    // object. It is guaranteed to be 32 bit integer, but it can be
+    // represented as either a smi or heap number.
+    set_representation(Representation::Tagged());
+    SetFlag(kDependsOnArrayLengths);
+    SetFlag(kUseGVN);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ArrayLength, "array_length")
+};
+
+
+class HBitNot: public HUnaryOperation {
+ public:
+  explicit HBitNot(HValue* value) : HUnaryOperation(value) {
+    set_representation(Representation::Integer32());
+    SetFlag(kUseGVN);
+    SetFlag(kTruncatingToInt32);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Integer32();
+  }
+  virtual HType CalculateInferredType() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(BitNot, "bit_not")
+};
+
+
+class HUnaryMathOperation: public HUnaryOperation {
+ public:
+  HUnaryMathOperation(HValue* value, MathFunctionId op)
+      : HUnaryOperation(value), op_(op) {
+    switch (op) {
+      case kMathFloor:
+      case kMathRound:
+      case kMathCeil:
+        set_representation(Representation::Integer32());
+        break;
+      case kMathAbs:
+        set_representation(Representation::Tagged());
+        SetFlag(kFlexibleRepresentation);
+        break;
+      case kMathSqrt:
+      default:
+        set_representation(Representation::Double());
+    }
+    SetFlag(kUseGVN);
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  virtual HType CalculateInferredType() const;
+
+  virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    switch (op_) {
+      case kMathFloor:
+      case kMathRound:
+      case kMathCeil:
+      case kMathSqrt:
+        return Representation::Double();
+        break;
+      case kMathAbs:
+        return representation();
+        break;
+      default:
+        return Representation::None();
+    }
+  }
+
+  virtual HValue* Canonicalize() {
+    // If the input is integer32 then we replace the floor instruction
+    // with its inputs.  This happens before the representation changes are
+    // introduced.
+    if (op() == kMathFloor) {
+      if (value()->representation().IsInteger32()) return value();
+    }
+    return this;
+  }
+
+  MathFunctionId op() const { return op_; }
+  const char* OpName() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary_math_operation")
+
+ private:
+  MathFunctionId op_;
+};
+
+
+class HLoadElements: public HUnaryOperation {
+ public:
+  explicit HLoadElements(HValue* value) : HUnaryOperation(value) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+    SetFlag(kDependsOnMaps);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements")
+};
+
+
+class HCheckMap: public HUnaryOperation {
+ public:
+  HCheckMap(HValue* value, Handle<Map> map)
+      : HUnaryOperation(value), map_(map) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+    SetFlag(kDependsOnMaps);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+  virtual void PrintDataTo(StringStream* stream) const;
+  virtual HType CalculateInferredType() const;
+
+#ifdef DEBUG
+  virtual void Verify() const;
+#endif
+
+  Handle<Map> map() const { return map_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check_map")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    HCheckMap* b = HCheckMap::cast(other);
+    return map_.is_identical_to(b->map());
+  }
+
+ private:
+  Handle<Map> map_;
+};
+
+
+class HCheckFunction: public HUnaryOperation {
+ public:
+  HCheckFunction(HValue* value, Handle<JSFunction> function)
+      : HUnaryOperation(value), target_(function) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+  virtual void PrintDataTo(StringStream* stream) const;
+  virtual HType CalculateInferredType() const;
+
+#ifdef DEBUG
+  virtual void Verify() const;
+#endif
+
+  Handle<JSFunction> target() const { return target_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check_function")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    HCheckFunction* b = HCheckFunction::cast(other);
+    return target_.is_identical_to(b->target());
+  }
+
+ private:
+  Handle<JSFunction> target_;
+};
+
+
+class HCheckInstanceType: public HUnaryOperation {
+ public:
+  // Check that the instance type is in the range [first, last] where
+  // both first and last are included.
+  HCheckInstanceType(HValue* value, InstanceType first, InstanceType last)
+      : HUnaryOperation(value), first_(first), last_(last) {
+    ASSERT(first <= last);
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+#ifdef DEBUG
+  virtual void Verify() const;
+#endif
+
+  static HCheckInstanceType* NewIsJSObjectOrJSFunction(HValue* value);
+
+  InstanceType first() const { return first_; }
+  InstanceType last() const { return last_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check_instance_type")
+
+ protected:
+  // TODO(ager): It could be nice to allow the ommision of instance
+  // type checks if we have already performed an instance type check
+  // with a larger range.
+  virtual bool DataEquals(HValue* other) const {
+    HCheckInstanceType* b = HCheckInstanceType::cast(other);
+    return (first_ == b->first()) && (last_ == b->last());
+  }
+
+ private:
+  InstanceType first_;
+  InstanceType last_;
+};
+
+
+class HCheckNonSmi: public HUnaryOperation {
+ public:
+  explicit HCheckNonSmi(HValue* value) : HUnaryOperation(value) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  virtual HType CalculateInferredType() const;
+
+#ifdef DEBUG
+  virtual void Verify() const;
+#endif
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check_non_smi")
+};
+
+
+class HCheckPrototypeMaps: public HUnaryOperation {
+ public:
+  HCheckPrototypeMaps(HValue* value,
+                      Handle<JSObject> holder,
+                      Handle<Map> receiver_map)
+      : HUnaryOperation(value),
+        holder_(holder),
+        receiver_map_(receiver_map) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+    SetFlag(kDependsOnMaps);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+#ifdef DEBUG
+  virtual void Verify() const;
+#endif
+
+  Handle<JSObject> holder() const { return holder_; }
+  Handle<Map> receiver_map() const { return receiver_map_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check_prototype_maps")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other);
+    return holder_.is_identical_to(b->holder()) &&
+        receiver_map_.is_identical_to(b->receiver_map());
+  }
+
+ private:
+  Handle<JSObject> holder_;
+  Handle<Map> receiver_map_;
+};
+
+
+class HCheckSmi: public HUnaryOperation {
+ public:
+  explicit HCheckSmi(HValue* value) : HUnaryOperation(value) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+  virtual HType CalculateInferredType() const;
+
+#ifdef DEBUG
+  virtual void Verify() const;
+#endif
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check_smi")
+};
+
+
+class HPhi: public HValue {
+ public:
+  explicit HPhi(int merged_index)
+      : inputs_(2),
+        merged_index_(merged_index),
+        phi_id_(-1) {
+    for (int i = 0; i < Representation::kNumRepresentations; i++) {
+      non_phi_uses_[i] = 0;
+      indirect_uses_[i] = 0;
+    }
+    ASSERT(merged_index >= 0);
+    set_representation(Representation::Tagged());
+    SetFlag(kFlexibleRepresentation);
+  }
+
+  virtual Representation InferredRepresentation() const {
+    bool double_occurred = false;
+    bool int32_occurred = false;
+    for (int i = 0; i < OperandCount(); ++i) {
+      HValue* value = OperandAt(i);
+      if (value->representation().IsDouble()) double_occurred = true;
+      if (value->representation().IsInteger32()) int32_occurred = true;
+      if (value->representation().IsTagged()) return Representation::Tagged();
+    }
+
+    if (double_occurred) return Representation::Double();
+    if (int32_occurred) return Representation::Integer32();
+    return Representation::None();
+  }
+
+  virtual Range* InferRange();
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return representation();
+  }
+  virtual HType CalculateInferredType() const;
+  virtual int OperandCount() const { return inputs_.length(); }
+  virtual HValue* OperandAt(int index) const { return inputs_[index]; }
+  HValue* GetRedundantReplacement() const;
+  void AddInput(HValue* value);
+
+  bool HasReceiverOperand();
+
+  int merged_index() const { return merged_index_; }
+
+  virtual const char* Mnemonic() const { return "phi"; }
+
+  virtual void PrintTo(StringStream* stream) const;
+
+#ifdef DEBUG
+  virtual void Verify() const;
+#endif
+
+  DECLARE_INSTRUCTION(Phi)
+
+  void InitRealUses(int id);
+  void AddNonPhiUsesFrom(HPhi* other);
+  void AddIndirectUsesTo(int* use_count);
+
+  int tagged_non_phi_uses() const {
+    return non_phi_uses_[Representation::kTagged];
+  }
+  int int32_non_phi_uses() const {
+    return non_phi_uses_[Representation::kInteger32];
+  }
+  int double_non_phi_uses() const {
+    return non_phi_uses_[Representation::kDouble];
+  }
+  int tagged_indirect_uses() const {
+    return indirect_uses_[Representation::kTagged];
+  }
+  int int32_indirect_uses() const {
+    return indirect_uses_[Representation::kInteger32];
+  }
+  int double_indirect_uses() const {
+    return indirect_uses_[Representation::kDouble];
+  }
+  int phi_id() { return phi_id_; }
+
+ protected:
+  virtual void DeleteFromGraph();
+  virtual void InternalSetOperandAt(int index, HValue* value) {
+    inputs_[index] = value;
+  }
+
+ private:
+  ZoneList<HValue*> inputs_;
+  int merged_index_;
+
+  int non_phi_uses_[Representation::kNumRepresentations];
+  int indirect_uses_[Representation::kNumRepresentations];
+  int phi_id_;
+};
+
+
+class HArgumentsObject: public HInstruction {
+ public:
+  HArgumentsObject() {
+    set_representation(Representation::Tagged());
+    SetFlag(kIsArguments);
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject, "arguments-object")
+};
+
+
+class HConstant: public HInstruction {
+ public:
+  HConstant(Handle<Object> handle, Representation r);
+
+  Handle<Object> handle() const { return handle_; }
+
+  virtual bool EmitAtUses() const { return !representation().IsDouble(); }
+  virtual void PrintDataTo(StringStream* stream) const;
+  virtual HType CalculateInferredType() const;
+  bool IsInteger() const { return handle_->IsSmi(); }
+  HConstant* CopyToRepresentation(Representation r) const;
+  HConstant* CopyToTruncatedInt32() const;
+  bool HasInteger32Value() const { return has_int32_value_; }
+  int32_t Integer32Value() const {
+    ASSERT(HasInteger32Value());
+    return int32_value_;
+  }
+  bool HasDoubleValue() const { return has_double_value_; }
+  double DoubleValue() const {
+    ASSERT(HasDoubleValue());
+    return double_value_;
+  }
+  bool HasStringValue() const { return handle_->IsString(); }
+
+  virtual intptr_t Hashcode() const {
+    ASSERT(!Heap::allow_allocation(false));
+    return reinterpret_cast<intptr_t>(*handle());
+  }
+
+#ifdef DEBUG
+  virtual void Verify() const { }
+#endif
+
+  DECLARE_CONCRETE_INSTRUCTION(Constant, "constant")
+
+ protected:
+  virtual Range* InferRange();
+
+  virtual bool DataEquals(HValue* other) const {
+    HConstant* other_constant = HConstant::cast(other);
+    return handle().is_identical_to(other_constant->handle());
+  }
+
+ private:
+  Handle<Object> handle_;
+  HType constant_type_;
+
+  // The following two values represent the int32 and the double value of the
+  // given constant if there is a lossless conversion between the constant
+  // and the specific representation.
+  bool has_int32_value_;
+  int32_t int32_value_;
+  bool has_double_value_;
+  double double_value_;
+};
+
+
+class HBinaryOperation: public HInstruction {
+ public:
+  HBinaryOperation(HValue* left, HValue* right) {
+    ASSERT(left != NULL && right != NULL);
+    SetOperandAt(0, left);
+    SetOperandAt(1, right);
+  }
+
+  HValue* left() const { return OperandAt(0); }
+  HValue* right() const { return OperandAt(1); }
+
+  // TODO(kasperl): Move these helpers to the IA-32 Lithium
+  // instruction sequence builder.
+  HValue* LeastConstantOperand() const {
+    if (IsCommutative() && left()->IsConstant()) return right();
+    return left();
+  }
+  HValue* MostConstantOperand() const {
+    if (IsCommutative() && left()->IsConstant()) return left();
+    return right();
+  }
+
+  virtual bool IsCommutative() const { return false; }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+  virtual int OperandCount() const { return operands_.length(); }
+  virtual HValue* OperandAt(int index) const { return operands_[index]; }
+
+  DECLARE_INSTRUCTION(BinaryOperation)
+
+ protected:
+  virtual void InternalSetOperandAt(int index, HValue* value) {
+    operands_[index] = value;
+  }
+
+ private:
+  HOperandVector<2> operands_;
+};
+
+
+class HApplyArguments: public HInstruction {
+ public:
+  HApplyArguments(HValue* function,
+                  HValue* receiver,
+                  HValue* length,
+                  HValue* elements) {
+    set_representation(Representation::Tagged());
+    SetOperandAt(0, function);
+    SetOperandAt(1, receiver);
+    SetOperandAt(2, length);
+    SetOperandAt(3, elements);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    // The length is untagged, all other inputs are tagged.
+    return (index == 2)
+        ? Representation::Integer32()
+        : Representation::Tagged();
+  }
+
+  HValue* function() const { return OperandAt(0); }
+  HValue* receiver() const { return OperandAt(1); }
+  HValue* length() const { return OperandAt(2); }
+  HValue* elements() const { return OperandAt(3); }
+
+  virtual int OperandCount() const { return operands_.length(); }
+  virtual HValue* OperandAt(int index) const { return operands_[index]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply_arguments")
+
+
+
+ protected:
+  virtual void InternalSetOperandAt(int index, HValue* value) {
+    operands_[index] = value;
+  }
+
+ private:
+  HOperandVector<4> operands_;
+};
+
+
+class HArgumentsElements: public HInstruction {
+ public:
+  HArgumentsElements() {
+    // The value produced by this instruction is a pointer into the stack
+    // that looks as if it was a smi because of alignment.
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments_elements")
+};
+
+
+class HArgumentsLength: public HUnaryOperation {
+ public:
+  explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
+    set_representation(Representation::Integer32());
+    SetFlag(kUseGVN);
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments_length")
+};
+
+
+class HAccessArgumentsAt: public HInstruction {
+ public:
+  HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+    SetOperandAt(0, arguments);
+    SetOperandAt(1, length);
+    SetOperandAt(2, index);
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    // The arguments elements is considered tagged.
+    return index == 0
+        ? Representation::Tagged()
+        : Representation::Integer32();
+  }
+
+  HValue* arguments() const { return operands_[0]; }
+  HValue* length() const { return operands_[1]; }
+  HValue* index() const { return operands_[2]; }
+
+  virtual int OperandCount() const { return operands_.length(); }
+  virtual HValue* OperandAt(int index) const { return operands_[index]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access_arguments_at")
+
+ protected:
+  virtual void InternalSetOperandAt(int index, HValue* value) {
+    operands_[index] = value;
+  }
+
+ private:
+  HOperandVector<3> operands_;
+};
+
+
+class HBoundsCheck: public HBinaryOperation {
+ public:
+  HBoundsCheck(HValue* index, HValue* length)
+      : HBinaryOperation(index, length) {
+    SetFlag(kUseGVN);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Integer32();
+  }
+
+#ifdef DEBUG
+  virtual void Verify() const;
+#endif
+
+  HValue* index() const { return left(); }
+  HValue* length() const { return right(); }
+
+  DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds_check")
+};
+
+
+class HBitwiseBinaryOperation: public HBinaryOperation {
+ public:
+  HBitwiseBinaryOperation(HValue* left, HValue* right)
+      : HBinaryOperation(left, right) {
+    // Default to truncating, Integer32, UseGVN.
+    set_representation(Representation::Integer32());
+    SetFlag(kTruncatingToInt32);
+    SetFlag(kUseGVN);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Integer32();
+  }
+
+  DECLARE_INSTRUCTION(BitwiseBinaryOperation)
+};
+
+
+class HArithmeticBinaryOperation: public HBinaryOperation {
+ public:
+  HArithmeticBinaryOperation(HValue* left, HValue* right)
+      : HBinaryOperation(left, right) {
+    set_representation(Representation::Tagged());
+    SetFlag(kFlexibleRepresentation);
+    SetFlagMask(AllSideEffects());
+  }
+
+  virtual void RepresentationChanged(Representation to) {
+    if (!to.IsTagged()) {
+      ClearFlagMask(AllSideEffects());
+      SetFlag(kUseGVN);
+    }
+  }
+
+  virtual HType CalculateInferredType() const;
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return representation();
+  }
+  virtual Representation InferredRepresentation() const {
+    if (left()->representation().Equals(right()->representation())) {
+      return left()->representation();
+    }
+    return HValue::InferredRepresentation();
+  }
+
+  DECLARE_INSTRUCTION(ArithmeticBinaryOperation)
+};
+
+
+class HCompare: public HBinaryOperation {
+ public:
+  HCompare(HValue* left, HValue* right, Token::Value token)
+      : HBinaryOperation(left, right), token_(token) {
+    ASSERT(Token::IsCompareOp(token));
+    set_representation(Representation::Tagged());
+    SetFlagMask(AllSideEffects());
+  }
+
+  void SetInputRepresentation(Representation r);
+  virtual bool EmitAtUses() const { return uses()->length() <= 1; }
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return input_representation_;
+  }
+  Representation GetInputRepresentation() const {
+    return input_representation_;
+  }
+  Token::Value token() const { return token_; }
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  virtual HType CalculateInferredType() const;
+
+  virtual intptr_t Hashcode() const {
+    return HValue::Hashcode() * 7 + token_;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(Compare, "compare")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    HCompare* comp = HCompare::cast(other);
+    return token_ == comp->token();
+  }
+
+ private:
+  Representation input_representation_;
+  Token::Value token_;
+};
+
+
+class HCompareJSObjectEq: public HBinaryOperation {
+ public:
+  HCompareJSObjectEq(HValue* left, HValue* right)
+      : HBinaryOperation(left, right) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+  }
+
+  virtual bool EmitAtUses() const { return uses()->length() <= 1; }
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+  virtual HType CalculateInferredType() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareJSObjectEq, "compare-js-object-eq")
+};
+
+
+class HUnaryPredicate: public HUnaryOperation {
+ public:
+  explicit HUnaryPredicate(HValue* value) : HUnaryOperation(value) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+  }
+  virtual bool EmitAtUses() const { return uses()->length() <= 1; }
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+  virtual HType CalculateInferredType() const;
+};
+
+
+class HIsNull: public HUnaryPredicate {
+ public:
+  HIsNull(HValue* value, bool is_strict)
+      : HUnaryPredicate(value), is_strict_(is_strict) { }
+
+  bool is_strict() const { return is_strict_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsNull, "is_null")
+
+ private:
+  bool is_strict_;
+};
+
+
+class HIsSmi: public HUnaryPredicate {
+ public:
+  explicit HIsSmi(HValue* value) : HUnaryPredicate(value) { }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsSmi, "is_smi")
+};
+
+
+class HHasInstanceType: public HUnaryPredicate {
+ public:
+  HHasInstanceType(HValue* value, InstanceType type)
+      : HUnaryPredicate(value), from_(type), to_(type) { }
+  HHasInstanceType(HValue* value, InstanceType from, InstanceType to)
+      : HUnaryPredicate(value), from_(from), to_(to) {
+    ASSERT(to == LAST_TYPE);  // Others not implemented yet in backend.
+  }
+
+  InstanceType from() { return from_; }
+  InstanceType to() { return to_; }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(HasInstanceType, "has_instance_type")
+
+ private:
+  InstanceType from_;
+  InstanceType to_;  // Inclusive range, not all combinations work.
+};
+
+
+class HHasCachedArrayIndex: public HUnaryPredicate {
+ public:
+  explicit HHasCachedArrayIndex(HValue* value) : HUnaryPredicate(value) { }
+
+  DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex, "has_cached_array_index")
+};
+
+
+class HClassOfTest: public HUnaryPredicate {
+ public:
+  HClassOfTest(HValue* value, Handle<String> class_name)
+      : HUnaryPredicate(value), class_name_(class_name) { }
+
+  DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class_of_test")
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  Handle<String> class_name() const { return class_name_; }
+
+ private:
+  Handle<String> class_name_;
+};
+
+
+class HTypeofIs: public HUnaryPredicate {
+ public:
+  HTypeofIs(HValue* value, Handle<String> type_literal)
+      : HUnaryPredicate(value), type_literal_(type_literal) { }
+
+  Handle<String> type_literal() { return type_literal_; }
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(TypeofIs, "typeof_is")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    HTypeofIs* b = HTypeofIs::cast(other);
+    return type_literal_.is_identical_to(b->type_literal_);
+  }
+
+ private:
+  Handle<String> type_literal_;
+};
+
+
+class HInstanceOf: public HBinaryOperation {
+ public:
+  HInstanceOf(HValue* left, HValue* right) : HBinaryOperation(left, right) {
+    set_representation(Representation::Tagged());
+    SetFlagMask(AllSideEffects());
+  }
+
+  virtual bool EmitAtUses() const { return uses()->length() <= 1; }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance_of")
+};
+
+
+class HAdd: public HArithmeticBinaryOperation {
+ public:
+  HAdd(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
+    SetFlag(kCanOverflow);
+  }
+
+  // Add is only commutative if two integer values are added and not if two
+  // tagged values are added (because it might be a String concatenation).
+  virtual bool IsCommutative() const {
+    return !representation().IsTagged();
+  }
+
+  virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
+
+  virtual HType CalculateInferredType() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(Add, "add")
+
+ protected:
+  virtual Range* InferRange();
+};
+
+
+class HSub: public HArithmeticBinaryOperation {
+ public:
+  HSub(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
+    SetFlag(kCanOverflow);
+  }
+
+  virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
+
+  DECLARE_CONCRETE_INSTRUCTION(Sub, "sub")
+
+ protected:
+  virtual Range* InferRange();
+};
+
+
+class HMul: public HArithmeticBinaryOperation {
+ public:
+  HMul(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
+    SetFlag(kCanOverflow);
+  }
+
+  virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
+
+  // Only commutative if it is certain that not two objects are multiplicated.
+  virtual bool IsCommutative() const {
+    return !representation().IsTagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(Mul, "mul")
+
+ protected:
+  virtual Range* InferRange();
+};
+
+
+class HMod: public HArithmeticBinaryOperation {
+ public:
+  HMod(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
+    SetFlag(kCanBeDivByZero);
+  }
+
+  virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
+
+  DECLARE_CONCRETE_INSTRUCTION(Mod, "mod")
+
+ protected:
+  virtual Range* InferRange();
+};
+
+
+class HDiv: public HArithmeticBinaryOperation {
+ public:
+  HDiv(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
+    SetFlag(kCanBeDivByZero);
+    SetFlag(kCanOverflow);
+  }
+
+  virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
+
+  DECLARE_CONCRETE_INSTRUCTION(Div, "div")
+
+ protected:
+  virtual Range* InferRange();
+};
+
+
+class HBitAnd: public HBitwiseBinaryOperation {
+ public:
+  HBitAnd(HValue* left, HValue* right)
+      : HBitwiseBinaryOperation(left, right) { }
+
+  virtual bool IsCommutative() const { return true; }
+  virtual HType CalculateInferredType() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(BitAnd, "bit_and")
+
+ protected:
+  virtual Range* InferRange();
+};
+
+
+class HBitXor: public HBitwiseBinaryOperation {
+ public:
+  HBitXor(HValue* left, HValue* right)
+      : HBitwiseBinaryOperation(left, right) { }
+
+  virtual bool IsCommutative() const { return true; }
+  virtual HType CalculateInferredType() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(BitXor, "bit_xor")
+};
+
+
+class HBitOr: public HBitwiseBinaryOperation {
+ public:
+  HBitOr(HValue* left, HValue* right)
+      : HBitwiseBinaryOperation(left, right) { }
+
+  virtual bool IsCommutative() const { return true; }
+  virtual HType CalculateInferredType() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(BitOr, "bit_or")
+
+ protected:
+  virtual Range* InferRange();
+};
+
+
+class HShl: public HBitwiseBinaryOperation {
+ public:
+  HShl(HValue* left, HValue* right)
+      : HBitwiseBinaryOperation(left, right) { }
+
+  virtual Range* InferRange();
+  virtual HType CalculateInferredType() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(Shl, "shl")
+};
+
+
+class HShr: public HBitwiseBinaryOperation {
+ public:
+  HShr(HValue* left, HValue* right)
+      : HBitwiseBinaryOperation(left, right) { }
+
+  virtual HType CalculateInferredType() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(Shr, "shr")
+};
+
+
+class HSar: public HBitwiseBinaryOperation {
+ public:
+  HSar(HValue* left, HValue* right)
+      : HBitwiseBinaryOperation(left, right) { }
+
+  virtual Range* InferRange();
+  virtual HType CalculateInferredType() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(Sar, "sar")
+};
+
+
+class HOsrEntry: public HInstruction {
+ public:
+  explicit HOsrEntry(int ast_id) : ast_id_(ast_id) {
+    SetFlag(kChangesOsrEntries);
+  }
+
+  int ast_id() const { return ast_id_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr_entry")
+
+ private:
+  int ast_id_;
+};
+
+
+class HParameter: public HInstruction {
+ public:
+  explicit HParameter(unsigned index) : index_(index) {
+    set_representation(Representation::Tagged());
+  }
+
+  unsigned index() const { return index_; }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
+
+ private:
+  unsigned index_;
+};
+
+
+class HCallStub: public HInstruction {
+ public:
+  HCallStub(CodeStub::Major major_key, int argument_count)
+      : major_key_(major_key),
+        argument_count_(argument_count),
+        transcendental_type_(TranscendentalCache::kNumberOfCaches) {
+    set_representation(Representation::Tagged());
+    SetFlagMask(AllSideEffects());
+  }
+
+  CodeStub::Major major_key() { return major_key_; }
+  int argument_count() { return argument_count_; }
+
+  void set_transcendental_type(TranscendentalCache::Type transcendental_type) {
+    transcendental_type_ = transcendental_type;
+  }
+  TranscendentalCache::Type transcendental_type() {
+    return transcendental_type_;
+  }
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(CallStub, "call_stub")
+
+ private:
+  CodeStub::Major major_key_;
+  int argument_count_;
+  TranscendentalCache::Type transcendental_type_;
+};
+
+
+class HUnknownOSRValue: public HInstruction {
+ public:
+  HUnknownOSRValue() { set_representation(Representation::Tagged()); }
+
+  DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown_osr_value")
+};
+
+
+class HLoadGlobal: public HInstruction {
+ public:
+  HLoadGlobal(Handle<JSGlobalPropertyCell> cell, bool check_hole_value)
+      : cell_(cell), check_hole_value_(check_hole_value) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+    SetFlag(kDependsOnGlobalVars);
+  }
+
+  Handle<JSGlobalPropertyCell>  cell() const { return cell_; }
+  bool check_hole_value() const { return check_hole_value_; }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  virtual intptr_t Hashcode() const {
+    ASSERT(!Heap::allow_allocation(false));
+    return reinterpret_cast<intptr_t>(*cell_);
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadGlobal, "load_global")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    HLoadGlobal* b = HLoadGlobal::cast(other);
+    return cell_.is_identical_to(b->cell());
+  }
+
+ private:
+  Handle<JSGlobalPropertyCell> cell_;
+  bool check_hole_value_;
+};
+
+
+class HStoreGlobal: public HUnaryOperation {
+ public:
+  HStoreGlobal(HValue* value, Handle<JSGlobalPropertyCell> cell)
+      : HUnaryOperation(value), cell_(cell) {
+    SetFlag(kChangesGlobalVars);
+  }
+
+  Handle<JSGlobalPropertyCell> cell() const { return cell_; }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreGlobal, "store_global")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    HStoreGlobal* b = HStoreGlobal::cast(other);
+    return cell_.is_identical_to(b->cell());
+  }
+
+ private:
+  Handle<JSGlobalPropertyCell> cell_;
+};
+
+
+class HLoadNamedField: public HUnaryOperation {
+ public:
+  HLoadNamedField(HValue* object, bool is_in_object, int offset)
+      : HUnaryOperation(object),
+        is_in_object_(is_in_object),
+        offset_(offset) {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+    if (is_in_object) {
+      SetFlag(kDependsOnInobjectFields);
+    } else {
+      SetFlag(kDependsOnBackingStoreFields);
+    }
+  }
+
+  HValue* object() const { return OperandAt(0); }
+  bool is_in_object() const { return is_in_object_; }
+  int offset() const { return offset_; }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load_named_field")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    HLoadNamedField* b = HLoadNamedField::cast(other);
+    return is_in_object_ == b->is_in_object_ && offset_ == b->offset_;
+  }
+
+ private:
+  bool is_in_object_;
+  int offset_;
+};
+
+
+class HLoadNamedGeneric: public HUnaryOperation {
+ public:
+  HLoadNamedGeneric(HValue* object, Handle<Object> name)
+      : HUnaryOperation(object), name_(name) {
+    set_representation(Representation::Tagged());
+    SetFlagMask(AllSideEffects());
+  }
+
+  HValue* object() const { return OperandAt(0); }
+  Handle<Object> name() const { return name_; }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load_named_generic")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    HLoadNamedGeneric* b = HLoadNamedGeneric::cast(other);
+    return name_.is_identical_to(b->name_);
+  }
+
+ private:
+  Handle<Object> name_;
+};
+
+
+class HLoadKeyed: public HBinaryOperation {
+ public:
+  HLoadKeyed(HValue* obj, HValue* key) : HBinaryOperation(obj, key) {
+    set_representation(Representation::Tagged());
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+  HValue* object() const { return OperandAt(0); }
+  HValue* key() const { return OperandAt(1); }
+
+  DECLARE_INSTRUCTION(LoadKeyed)
+};
+
+
+class HLoadKeyedFastElement: public HLoadKeyed {
+ public:
+  HLoadKeyedFastElement(HValue* obj, HValue* key) : HLoadKeyed(obj, key) {
+    SetFlag(kDependsOnArrayElements);
+    SetFlag(kUseGVN);
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    // The key is supposed to be Integer32.
+    return (index == 1) ? Representation::Integer32()
+        : Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement,
+                               "load_keyed_fast_element")
+};
+
+
+class HLoadKeyedGeneric: public HLoadKeyed {
+ public:
+  HLoadKeyedGeneric(HValue* obj, HValue* key) : HLoadKeyed(obj, key) {
+    SetFlagMask(AllSideEffects());
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load_keyed_generic")
+};
+
+
+class HStoreNamed: public HBinaryOperation {
+ public:
+  HStoreNamed(HValue* obj, Handle<Object> name, HValue* val)
+      : HBinaryOperation(obj, val), name_(name) {
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  HValue* object() const { return OperandAt(0); }
+  Handle<Object> name() const { return name_; }
+  HValue* value() const { return OperandAt(1); }
+  void set_value(HValue* value) { SetOperandAt(1, value); }
+
+  DECLARE_INSTRUCTION(StoreNamed)
+
+ protected:
+  virtual bool DataEquals(HValue* other) const {
+    HStoreNamed* b = HStoreNamed::cast(other);
+    return name_.is_identical_to(b->name_);
+  }
+
+ private:
+  Handle<Object> name_;
+};
+
+
+class HStoreNamedField: public HStoreNamed {
+ public:
+  HStoreNamedField(HValue* obj,
+                   Handle<Object> name,
+                   HValue* val,
+                   bool in_object,
+                   int offset)
+      : HStoreNamed(obj, name, val),
+        is_in_object_(in_object),
+        offset_(offset) {
+    if (is_in_object_) {
+      SetFlag(kChangesInobjectFields);
+    } else {
+      SetFlag(kChangesBackingStoreFields);
+    }
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store_named_field")
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return  Representation::Tagged();
+  }
+  virtual void PrintDataTo(StringStream* stream) const;
+
+  bool is_in_object() const { return is_in_object_; }
+  int offset() const { return offset_; }
+  Handle<Map> transition() const { return transition_; }
+  void set_transition(Handle<Map> map) { transition_ = map; }
+
+ private:
+  bool is_in_object_;
+  int offset_;
+  Handle<Map> transition_;
+};
+
+
+class HStoreNamedGeneric: public HStoreNamed {
+ public:
+  HStoreNamedGeneric(HValue* obj, Handle<Object> name, HValue* val)
+      : HStoreNamed(obj, name, val) {
+    SetFlagMask(AllSideEffects());
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store_named_generic")
+};
+
+
+class HStoreKeyed: public HInstruction {
+ public:
+  HStoreKeyed(HValue* obj, HValue* key, HValue* val) {
+    SetOperandAt(0, obj);
+    SetOperandAt(1, key);
+    SetOperandAt(2, val);
+  }
+
+  virtual void PrintDataTo(StringStream* stream) const;
+  virtual int OperandCount() const { return operands_.length(); }
+  virtual HValue* OperandAt(int index) const { return operands_[index]; }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  HValue* object() const { return OperandAt(0); }
+  HValue* key() const { return OperandAt(1); }
+  HValue* value() const { return OperandAt(2); }
+
+  DECLARE_INSTRUCTION(StoreKeyed)
+
+ protected:
+  virtual void InternalSetOperandAt(int index, HValue* value) {
+    operands_[index] = value;
+  }
+
+ private:
+  HOperandVector<3> operands_;
+};
+
+
+class HStoreKeyedFastElement: public HStoreKeyed {
+ public:
+  HStoreKeyedFastElement(HValue* obj, HValue* key, HValue* val)
+      : HStoreKeyed(obj, key, val) {
+    SetFlag(kChangesArrayElements);
+  }
+
+  bool NeedsWriteBarrier() const {
+    return !value()->type().IsSmi();
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    // The key is supposed to be Integer32.
+    return (index == 1) ? Representation::Integer32()
+        : Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement,
+                               "store_keyed_fast_element")
+};
+
+
+class HStoreKeyedGeneric: public HStoreKeyed {
+ public:
+  HStoreKeyedGeneric(HValue* obj, HValue* key, HValue* val)
+      : HStoreKeyed(obj, key, val) {
+    SetFlagMask(AllSideEffects());
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store_keyed_generic")
+};
+
+
+class HMaterializedLiteral: public HInstruction {
+ public:
+  HMaterializedLiteral(int index, int depth)
+      : literal_index_(index), depth_(depth) {
+    set_representation(Representation::Tagged());
+  }
+
+  int literal_index() const { return literal_index_; }
+  int depth() const { return depth_; }
+
+  DECLARE_INSTRUCTION(MaterializedLiteral)
+
+ private:
+  int literal_index_;
+  int depth_;
+};
+
+
+class HArrayLiteral: public HMaterializedLiteral {
+ public:
+  HArrayLiteral(Handle<FixedArray> constant_elements,
+                int length,
+                int literal_index,
+                int depth)
+      : HMaterializedLiteral(literal_index, depth),
+        length_(length),
+        constant_elements_(constant_elements) {}
+
+  Handle<FixedArray> constant_elements() const { return constant_elements_; }
+  int length() const { return length_; }
+
+  bool IsCopyOnWrite() const;
+
+  DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array_literal")
+
+ private:
+  int length_;
+  Handle<FixedArray> constant_elements_;
+};
+
+
+class HObjectLiteral: public HMaterializedLiteral {
+ public:
+  HObjectLiteral(Handle<FixedArray> constant_properties,
+                 bool fast_elements,
+                 int literal_index,
+                 int depth)
+      : HMaterializedLiteral(literal_index, depth),
+        constant_properties_(constant_properties),
+        fast_elements_(fast_elements) {}
+
+  Handle<FixedArray> constant_properties() const {
+    return constant_properties_;
+  }
+  bool fast_elements() const { return fast_elements_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object_literal")
+
+ private:
+  Handle<FixedArray> constant_properties_;
+  bool fast_elements_;
+};
+
+
+class HRegExpLiteral: public HMaterializedLiteral {
+ public:
+  HRegExpLiteral(Handle<String> pattern,
+                 Handle<String> flags,
+                 int literal_index)
+      : HMaterializedLiteral(literal_index, 0),
+        pattern_(pattern),
+        flags_(flags) { }
+
+  Handle<String> pattern() { return pattern_; }
+  Handle<String> flags() { return flags_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp_literal")
+
+ private:
+  Handle<String> pattern_;
+  Handle<String> flags_;
+};
+
+
+class HFunctionLiteral: public HInstruction {
+ public:
+  HFunctionLiteral(Handle<SharedFunctionInfo> shared, bool pretenure)
+      : shared_info_(shared), pretenure_(pretenure) {
+    set_representation(Representation::Tagged());
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function_literal")
+
+  Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
+  bool pretenure() const { return pretenure_; }
+
+ private:
+  Handle<SharedFunctionInfo> shared_info_;
+  bool pretenure_;
+};
+
+
+class HTypeof: public HUnaryOperation {
+ public:
+  explicit HTypeof(HValue* value) : HUnaryOperation(value) {
+    set_representation(Representation::Tagged());
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof")
+};
+
+
+class HValueOf: public HUnaryOperation {
+ public:
+  explicit HValueOf(HValue* value) : HUnaryOperation(value) {
+    set_representation(Representation::Tagged());
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value_of")
+};
+
+
+class HDeleteProperty: public HBinaryOperation {
+ public:
+  HDeleteProperty(HValue* obj, HValue* key)
+      : HBinaryOperation(obj, key) {
+    set_representation(Representation::Tagged());
+    SetFlagMask(AllSideEffects());
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete_property")
+
+  HValue* object() const { return left(); }
+  HValue* key() const { return right(); }
+};
+
+#undef DECLARE_INSTRUCTION
+#undef DECLARE_CONCRETE_INSTRUCTION
+
+} }  // namespace v8::internal
+
+#endif  // V8_HYDROGEN_INSTRUCTIONS_H_