| Index: src/hydrogen-instructions.h
|
| diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..625841e6474383c834652b8648738ddff601ab40
|
| --- /dev/null
|
| +++ b/src/hydrogen-instructions.h
|
| @@ -0,0 +1,2886 @@
|
| +// 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() ==
|
| + Isolate::Current()->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,
|
| + const Runtime::Function* c_function,
|
| + int argument_count)
|
| + : HCall(argument_count), c_function_(c_function), name_(name) { }
|
| + virtual void PrintDataTo(StringStream* stream) const;
|
| +
|
| + const Runtime::Function* function() const { return c_function_; }
|
| + Handle<String> name() const { return name_; }
|
| +
|
| + DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call_runtime")
|
| +
|
| + private:
|
| + const 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_
|
|
|