diff options
Diffstat (limited to 'deps/v8/src/hydrogen-instructions.h')
-rw-r--r-- | deps/v8/src/hydrogen-instructions.h | 2885 |
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_ |