// Copyright 2011 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 // HInstanceOfKnownGlobal // HLoadKeyed // HLoadKeyedFastElement // HLoadKeyedGeneric // HPower // HStoreNamed // HStoreNamedField // HStoreNamedGeneric // HStringCharCodeAt // HBlockEntry // HCall // HCallConstantFunction // HCallFunction // HCallGlobal // HCallKeyed // HCallKnownGlobal // HCallNamed // HCallNew // HCallRuntime // HCallStub // HCheckPrototypeMaps // HConstant // HControlInstruction // HDeoptimize // HGoto // HUnaryControlInstruction // HCompareMap // HReturn // HTest // HThrow // HEnterInlined // HFunctionLiteral // HGlobalObject // HGlobalReceiver // HLeaveInlined // HLoadContextSlot // HLoadGlobal // HMaterializedLiteral // HArrayLiteral // HObjectLiteral // HRegExpLiteral // HOsrEntry // HParameter // HSimulate // HStackCheck // HStoreKeyed // HStoreKeyedFastElement // HStoreKeyedGeneric // HUnaryOperation // HBitNot // HChange // HCheckFunction // HCheckInstanceType // HCheckMap // HCheckNonSmi // HCheckSmi // HDeleteProperty // HFixedArrayLength // HJSArrayLength // HLoadElements // HLoadFunctionPrototype // HLoadNamedField // HLoadNamedGeneric // HPushArgument // HStringLength // HTypeof // HUnaryMathOperation // HUnaryPredicate // HClassOfTest // HHasCachedArrayIndex // HHasInstanceType // HIsNull // HIsObject // HIsSmi // HTypeofIs // 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(ArrayLiteral) \ V(BitAnd) \ V(BitNot) \ V(BitOr) \ V(BitXor) \ V(BlockEntry) \ V(BoundsCheck) \ 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(CompareMap) \ V(Constant) \ V(DeleteProperty) \ V(Deoptimize) \ V(Div) \ V(EnterInlined) \ V(FixedArrayLength) \ V(FunctionLiteral) \ V(GlobalObject) \ V(GlobalReceiver) \ V(Goto) \ V(InstanceOf) \ V(InstanceOfKnownGlobal) \ V(IsNull) \ V(IsObject) \ V(IsSmi) \ V(HasInstanceType) \ V(HasCachedArrayIndex) \ V(JSArrayLength) \ V(ClassOfTest) \ V(LeaveInlined) \ V(LoadContextSlot) \ V(LoadElements) \ V(LoadFunctionPrototype) \ V(LoadGlobal) \ V(LoadKeyedFastElement) \ V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ V(Mod) \ V(Mul) \ V(ObjectLiteral) \ V(OsrEntry) \ V(Parameter) \ V(Power) \ 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(StringCharCodeAt) \ V(StringLength) \ V(Sub) \ V(Test) \ 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(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 class HOperandVector : public EmbeddedVector { public: HOperandVector() : EmbeddedVector(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); } // Adds a constant to the lower and upper bound of the range. void AddConstant(int32_t value); 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); } // Compute a new result range and return true, if the operation // can overflow. 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_ & 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 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* 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 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 // Returns whether this is some kind of deoptimizing check // instruction. virtual bool IsCheckInstruction() const { return false; } 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: HControlInstruction(HBasicBlock* first, HBasicBlock* second) : first_successor_(first), second_successor_(second) { } HBasicBlock* FirstSuccessor() const { return first_successor_; } HBasicBlock* SecondSuccessor() const { return second_successor_; } virtual void PrintDataTo(StringStream* stream) const; DECLARE_INSTRUCTION(ControlInstruction) private: HBasicBlock* first_successor_; HBasicBlock* second_successor_; }; class HDeoptimize: public HControlInstruction { public: HDeoptimize() : HControlInstruction(NULL, NULL) { } DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize") }; class HGoto: public HControlInstruction { public: explicit HGoto(HBasicBlock* target) : HControlInstruction(target, NULL), include_stack_check_(false) { } void set_include_stack_check(bool include_stack_check) { include_stack_check_ = include_stack_check; } bool include_stack_check() const { return include_stack_check_; } DECLARE_CONCRETE_INSTRUCTION(Goto, "goto") private: bool include_stack_check_; }; class HUnaryControlInstruction: public HControlInstruction { public: explicit HUnaryControlInstruction(HValue* value, HBasicBlock* true_target, HBasicBlock* false_target) : HControlInstruction(true_target, false_target) { SetOperandAt(0, value); } virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); } virtual void PrintDataTo(StringStream* stream) const; 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 HTest: public HUnaryControlInstruction { public: HTest(HValue* value, HBasicBlock* true_target, HBasicBlock* false_target) : HUnaryControlInstruction(value, true_target, false_target) { ASSERT(true_target != NULL && false_target != NULL); } virtual Representation RequiredInputRepresentation(int index) const { return Representation::None(); } DECLARE_CONCRETE_INSTRUCTION(Test, "test") }; class HCompareMap: public HUnaryControlInstruction { public: HCompareMap(HValue* value, Handle map, HBasicBlock* true_target, HBasicBlock* false_target) : HUnaryControlInstruction(value, true_target, false_target), map_(map) { ASSERT(true_target != NULL); ASSERT(false_target != NULL); ASSERT(!map.is_null()); } virtual void PrintDataTo(StringStream* stream) const; Handle map() const { return map_; } DECLARE_CONCRETE_INSTRUCTION(CompareMap, "compare_map") private: Handle map_; }; class HReturn: public HUnaryControlInstruction { public: explicit HReturn(HValue* value) : HUnaryControlInstruction(value, NULL, NULL) { } DECLARE_CONCRETE_INSTRUCTION(Return, "return") }; class HThrow: public HUnaryControlInstruction { public: explicit HThrow(HValue* value) : HUnaryControlInstruction(value, NULL, NULL) { } 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_length) : ast_id_(ast_id), pop_count_(pop_count), environment_length_(environment_length), 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_length() const { return environment_length_; } int pop_count() const { return pop_count_; } const ZoneList* 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_length_; ZoneList values_; ZoneList assigned_indexes_; }; class HStackCheck: public HInstruction { public: HStackCheck() { } DECLARE_CONCRETE_INSTRUCTION(Throw, "stack_check") }; class HEnterInlined: public HInstruction { public: HEnterInlined(Handle closure, FunctionLiteral* function) : closure_(closure), function_(function) { } virtual void PrintDataTo(StringStream* stream) const; Handle closure() const { return closure_; } FunctionLiteral* function() const { return function_; } DECLARE_CONCRETE_INSTRUCTION(EnterInlined, "enter_inlined") private: Handle 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 arguments_; }; class HCallConstantFunction: public HCall { public: HCallConstantFunction(Handle function, int argument_count) : HCall(argument_count), function_(function) { } Handle 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 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 name, int argument_count) : HCall(argument_count), name_(name) { } virtual void PrintDataTo(StringStream* stream) const; Handle name() const { return name_; } DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call_named") private: Handle 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 name, int argument_count) : HCall(argument_count), name_(name) { } virtual void PrintDataTo(StringStream* stream) const; Handle name() const { return name_; } DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call_global") private: Handle name_; }; class HCallKnownGlobal: public HCall { public: HCallKnownGlobal(Handle target, int argument_count) : HCall(argument_count), target_(target) { } Handle target() const { return target_; } DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal, "call_known_global") private: Handle 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 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 name() const { return name_; } DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call_runtime") private: Runtime::Function* c_function_; Handle name_; }; class HJSArrayLength: public HUnaryOperation { public: explicit HJSArrayLength(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(JSArrayLength, "js_array_length") }; class HFixedArrayLength: public HUnaryOperation { public: explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) { set_representation(Representation::Tagged()); SetFlag(kDependsOnArrayLengths); SetFlag(kUseGVN); } virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); } DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed_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, BuiltinFunctionId 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: case kMathPowHalf: case kMathLog: case kMathSin: case kMathCos: set_representation(Representation::Double()); break; default: UNREACHABLE(); } 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: case kMathPowHalf: case kMathLog: case kMathSin: case kMathCos: 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; } BuiltinFunctionId op() const { return op_; } const char* OpName() const; DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary_math_operation") protected: virtual bool DataEquals(HValue* other) const { HUnaryMathOperation* b = HUnaryMathOperation::cast(other); return op_ == b->op(); } private: BuiltinFunctionId 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) : HUnaryOperation(value), map_(map) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetFlag(kDependsOnMaps); } virtual bool IsCheckInstruction() const { return true; } 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() 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_; }; class HCheckFunction: public HUnaryOperation { public: HCheckFunction(HValue* value, Handle function) : HUnaryOperation(value), target_(function) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); } virtual bool IsCheckInstruction() const { return true; } 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 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 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); if ((FIRST_STRING_TYPE < first && last <= LAST_STRING_TYPE) || (FIRST_STRING_TYPE <= first && last < LAST_STRING_TYPE)) { // A particular string instance type can change because of GC or // externalization, but the value still remains a string. SetFlag(kDependsOnMaps); } } virtual bool IsCheckInstruction() const { return true; } 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 bool IsCheckInstruction() const { return true; } 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 HInstruction { public: HCheckPrototypeMaps(Handle prototype, Handle holder) : prototype_(prototype), holder_(holder) { SetFlag(kUseGVN); SetFlag(kDependsOnMaps); } virtual bool IsCheckInstruction() const { return true; } #ifdef DEBUG virtual void Verify() const; #endif Handle prototype() const { return prototype_; } Handle holder() const { return holder_; } DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check_prototype_maps") virtual intptr_t Hashcode() const { ASSERT(!Heap::IsAllocationAllowed()); intptr_t hash = reinterpret_cast(*prototype()); hash = 17 * hash + reinterpret_cast(*holder()); return hash; } protected: virtual bool DataEquals(HValue* other) const { HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other); return prototype_.is_identical_to(b->prototype()) && holder_.is_identical_to(b->holder()); } private: Handle prototype_; Handle holder_; }; class HCheckSmi: public HUnaryOperation { public: explicit HCheckSmi(HValue* value) : HUnaryOperation(value) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); } virtual bool IsCheckInstruction() const { return true; } 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 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 handle, Representation r); Handle handle() const { return handle_; } bool InOldSpace() const { return !Heap::InNewSpace(*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(*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 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 bool IsCheckInstruction() const { return true; } 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) { set_representation(Representation::Tagged()); SetFlag(kFlexibleRepresentation); SetFlagMask(AllSideEffects()); } virtual Representation RequiredInputRepresentation(int index) const { return representation(); } virtual void RepresentationChanged(Representation to) { if (!to.IsTagged()) { ASSERT(to.IsInteger32()); ClearFlagMask(AllSideEffects()); SetFlag(kTruncatingToInt32); SetFlag(kUseGVN); } } HType CalculateInferredType() const; 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") protected: virtual bool DataEquals(HValue* other) const { HIsNull* b = HIsNull::cast(other); return is_strict_ == b->is_strict(); } private: bool is_strict_; }; class HIsObject: public HUnaryPredicate { public: explicit HIsObject(HValue* value) : HUnaryPredicate(value) { } DECLARE_CONCRETE_INSTRUCTION(IsObject, "is_object") }; 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") protected: virtual bool DataEquals(HValue* other) const { HHasInstanceType* b = HHasInstanceType::cast(other); return (from_ == b->from()) && (to_ == b->to()); } 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 class_name) : HUnaryPredicate(value), class_name_(class_name) { } DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class_of_test") virtual void PrintDataTo(StringStream* stream) const; Handle class_name() const { return class_name_; } protected: virtual bool DataEquals(HValue* other) const { HClassOfTest* b = HClassOfTest::cast(other); return class_name_.is_identical_to(b->class_name_); } private: Handle class_name_; }; class HTypeofIs: public HUnaryPredicate { public: HTypeofIs(HValue* value, Handle type_literal) : HUnaryPredicate(value), type_literal_(type_literal) { } Handle 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 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 HInstanceOfKnownGlobal: public HUnaryOperation { public: HInstanceOfKnownGlobal(HValue* left, Handle right) : HUnaryOperation(left), function_(right) { set_representation(Representation::Tagged()); SetFlagMask(AllSideEffects()); } Handle function() { return function_; } virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); } DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal, "instance_of_known_global") private: Handle function_; }; class HPower: public HBinaryOperation { public: HPower(HValue* left, HValue* right) : HBinaryOperation(left, right) { set_representation(Representation::Double()); SetFlag(kUseGVN); } virtual Representation RequiredInputRepresentation(int index) const { return (index == 1) ? Representation::None() : Representation::Double(); } DECLARE_CONCRETE_INSTRUCTION(Power, "power") }; 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 cell, bool check_hole_value) : cell_(cell), check_hole_value_(check_hole_value) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetFlag(kDependsOnGlobalVars); } Handle 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(*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 cell_; bool check_hole_value_; }; class HStoreGlobal: public HUnaryOperation { public: HStoreGlobal(HValue* value, Handle cell) : HUnaryOperation(value), cell_(cell) { SetFlag(kChangesGlobalVars); } Handle 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 cell_; }; class HLoadContextSlot: public HInstruction { public: HLoadContextSlot(int context_chain_length , int slot_index) : context_chain_length_(context_chain_length), slot_index_(slot_index) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetFlag(kDependsOnCalls); } int context_chain_length() const { return context_chain_length_; } int slot_index() const { return slot_index_; } virtual void PrintDataTo(StringStream* stream) const; virtual intptr_t Hashcode() const { return context_chain_length() * 29 + slot_index(); } DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load_context_slot") protected: virtual bool DataEquals(HValue* other) const { HLoadContextSlot* b = HLoadContextSlot::cast(other); return (context_chain_length() == b->context_chain_length()) && (slot_index() == b->slot_index()); } private: int context_chain_length_; int slot_index_; }; 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 name) : HUnaryOperation(object), name_(name) { set_representation(Representation::Tagged()); SetFlagMask(AllSideEffects()); } HValue* object() const { return OperandAt(0); } Handle 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 name_; }; class HLoadFunctionPrototype: public HUnaryOperation { public: explicit HLoadFunctionPrototype(HValue* function) : HUnaryOperation(function) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetFlag(kDependsOnCalls); } HValue* function() const { return OperandAt(0); } virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); } DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load_function_prototype") }; 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") }; static inline bool StoringValueNeedsWriteBarrier(HValue* value) { return !value->type().IsSmi() && !(value->IsConstant() && HConstant::cast(value)->InOldSpace()); } class HStoreNamed: public HBinaryOperation { public: HStoreNamed(HValue* obj, Handle 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 name() const { return name_; } HValue* value() const { return OperandAt(1); } void set_value(HValue* value) { SetOperandAt(1, value); } bool NeedsWriteBarrier() const { return StoringValueNeedsWriteBarrier(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 name_; }; class HStoreNamedField: public HStoreNamed { public: HStoreNamedField(HValue* obj, Handle 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 transition() const { return transition_; } void set_transition(Handle map) { transition_ = map; } private: bool is_in_object_; int offset_; Handle transition_; }; class HStoreNamedGeneric: public HStoreNamed { public: HStoreNamedGeneric(HValue* obj, Handle 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); } bool NeedsWriteBarrier() const { return StoringValueNeedsWriteBarrier(value()); } 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); } 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 HStringCharCodeAt: public HBinaryOperation { public: HStringCharCodeAt(HValue* string, HValue* index) : HBinaryOperation(string, index) { set_representation(Representation::Integer32()); SetFlag(kUseGVN); } virtual Representation RequiredInputRepresentation(int index) const { // The index is supposed to be Integer32. return (index == 1) ? Representation::Integer32() : Representation::Tagged(); } virtual bool DataEquals(HValue* other) const { return true; } HValue* string() const { return OperandAt(0); } HValue* index() const { return OperandAt(1); } DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string_char_code_at") protected: virtual Range* InferRange() { return new Range(0, String::kMaxUC16CharCode); } }; class HStringLength: public HUnaryOperation { public: explicit HStringLength(HValue* string) : HUnaryOperation(string) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); } virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); } virtual HType CalculateInferredType() const { STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); return HType::Smi(); } virtual bool DataEquals(HValue* other) const { return true; } DECLARE_CONCRETE_INSTRUCTION(StringLength, "string_length") protected: virtual Range* InferRange() { return new Range(0, String::kMaxLength); } }; 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 constant_elements, int length, int literal_index, int depth) : HMaterializedLiteral(literal_index, depth), length_(length), constant_elements_(constant_elements) {} Handle constant_elements() const { return constant_elements_; } int length() const { return length_; } bool IsCopyOnWrite() const; DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array_literal") private: int length_; Handle constant_elements_; }; class HObjectLiteral: public HMaterializedLiteral { public: HObjectLiteral(Handle constant_properties, bool fast_elements, int literal_index, int depth) : HMaterializedLiteral(literal_index, depth), constant_properties_(constant_properties), fast_elements_(fast_elements) {} Handle constant_properties() const { return constant_properties_; } bool fast_elements() const { return fast_elements_; } DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object_literal") private: Handle constant_properties_; bool fast_elements_; }; class HRegExpLiteral: public HMaterializedLiteral { public: HRegExpLiteral(Handle pattern, Handle flags, int literal_index) : HMaterializedLiteral(literal_index, 0), pattern_(pattern), flags_(flags) { } Handle pattern() { return pattern_; } Handle flags() { return flags_; } DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp_literal") private: Handle pattern_; Handle flags_; }; class HFunctionLiteral: public HInstruction { public: HFunctionLiteral(Handle shared, bool pretenure) : shared_info_(shared), pretenure_(pretenure) { set_representation(Representation::Tagged()); } DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function_literal") Handle shared_info() const { return shared_info_; } bool pretenure() const { return pretenure_; } private: Handle 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_