summaryrefslogtreecommitdiff
path: root/deps/v8/src/hydrogen-instructions.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/hydrogen-instructions.h')
-rw-r--r--deps/v8/src/hydrogen-instructions.h2885
1 files changed, 2885 insertions, 0 deletions
diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h
new file mode 100644
index 0000000000..ff1ab1a36e
--- /dev/null
+++ b/deps/v8/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_