blob: eebec5a9e272c6a4e7b670ceb206a5d0d6e09b5d [file] [log] [blame]
// 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
// HInstanceOfKnownGlobal
// HLoadKeyed
// HLoadKeyedFastElement
// HLoadKeyedGeneric
// HPower
// HStoreNamed
// HStoreNamedField
// HStoreNamedGeneric
// HBlockEntry
// HCall
// HCallConstantFunction
// HCallFunction
// HCallGlobal
// HCallKeyed
// HCallKnownGlobal
// HCallNamed
// HCallNew
// HCallRuntime
// HCallStub
// HCheckPrototypeMaps
// HConstant
// HControlInstruction
// HDeoptimize
// HGoto
// HUnaryControlInstruction
// HBranch
// HCompareMapAndBranch
// HReturn
// 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
// HTypeofIs
// HLoadNamedField
// HLoadNamedGeneric
// HLoadFunctionPrototype
// HPushArgument
// HTypeof
// HUnaryMathOperation
// HUnaryPredicate
// HClassOfTest
// HHasCachedArrayIndex
// HHasInstanceType
// HIsNull
// HIsObject
// 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(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(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(LoadGlobal) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadNamedField) \
V(LoadNamedGeneric) \
V(LoadFunctionPrototype) \
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(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(FunctionPrototypes) \
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);
}
// 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>(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
// 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:
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_; }
HBasicBlock* true_destination() const { return true_destination_; }
HBasicBlock* false_destination() const { return false_destination_; }
virtual void PrintDataTo(StringStream* stream) const;
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_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<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_length_;
ZoneList<HValue*> values_;
ZoneList<int> assigned_indexes_;
};
class HStackCheck: public HInstruction {
public:
HStackCheck() { }
DECLARE_CONCRETE_INSTRUCTION(Throw, "stack_check")
};
class HEnterInlined: public HInstruction {
public:
HEnterInlined(Handle<JSFunction> closure, FunctionLiteral* function)
: closure_(closure), function_(function) {
}
virtual void PrintDataTo(StringStream* stream) const;
Handle<JSFunction> closure() const { return closure_; }
FunctionLiteral* function() const { return function_; }
DECLARE_CONCRETE_INSTRUCTION(EnterInlined, "enter_inlined")
private:
Handle<JSFunction> closure_;
FunctionLiteral* function_;
};
class HLeaveInlined: public HInstruction {
public:
HLeaveInlined() {}
DECLARE_CONCRETE_INSTRUCTION(LeaveInlined, "leave_inlined")
};
class HPushArgument: public HUnaryOperation {
public:
explicit HPushArgument(HValue* value)
: HUnaryOperation(value), argument_index_(-1) {
set_representation(Representation::Tagged());
}
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
virtual void PrintDataTo(StringStream* stream) const;
HValue* argument() const { return OperandAt(0); }
int argument_index() const { return argument_index_; }
void set_argument_index(int index) {
ASSERT(argument_index_ == -1 || index == argument_index_);
argument_index_ = index;
}
DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push_argument")
private:
int argument_index_;
};
class HGlobalObject: public HInstruction {
public:
HGlobalObject() {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetFlag(kDependsOnCalls);
}
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global_object")
};
class HGlobalReceiver: public HInstruction {
public:
HGlobalReceiver() {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetFlag(kDependsOnCalls);
}
DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global_receiver")
};
class HCall: public HInstruction {
public:
// Construct a call with uninitialized arguments. The argument count
// includes the receiver.
explicit HCall(int count);
virtual HType CalculateInferredType() const { return HType::Tagged(); }
// TODO(3190496): This needs a cleanup. We don't want the arguments
// be operands of the call instruction. This results in bad code quality.
virtual int argument_count() const { return arguments_.length(); }
virtual int OperandCount() const { return argument_count(); }
virtual HValue* OperandAt(int index) const { return arguments_[index]; }
virtual HPushArgument* PushArgumentAt(int index) const {
return HPushArgument::cast(OperandAt(index));
}
virtual HValue* ArgumentAt(int index) const {
return PushArgumentAt(index)->argument();
}
virtual void SetArgumentAt(int index, HPushArgument* push_argument);
virtual void PrintDataTo(StringStream* stream) const;
DECLARE_INSTRUCTION(Call)
protected:
virtual void InternalSetOperandAt(int index, HValue* value) {
arguments_[index] = value;
}
int argument_count_;
Vector<HValue*> arguments_;
};
class HCallConstantFunction: public HCall {
public:
HCallConstantFunction(Handle<JSFunction> function, int argument_count)
: HCall(argument_count), function_(function) { }
Handle<JSFunction> function() const { return function_; }
bool IsApplyFunction() const {
return function_->code() == Builtins::builtin(Builtins::FunctionApply);
}
virtual void PrintDataTo(StringStream* stream) const;
DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction, "call_constant_function")
private:
Handle<JSFunction> function_;
};
class HCallKeyed: public HCall {
public:
HCallKeyed(HValue* key, int argument_count)
: HCall(argument_count + 1) {
SetOperandAt(0, key);
}
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
// TODO(3190496): This is a hack to get an additional operand that
// is not an argument to work with the current setup. This _needs_ a cleanup.
// (see HCall)
virtual void PrintDataTo(StringStream* stream) const;
HValue* key() const { return OperandAt(0); }
virtual int argument_count() const { return arguments_.length() - 1; }
virtual int OperandCount() const { return arguments_.length(); }
virtual HValue* OperandAt(int index) const { return arguments_[index]; }
virtual HPushArgument* PushArgumentAt(int index) const {
return HPushArgument::cast(OperandAt(index + 1));
}
virtual void SetArgumentAt(int index, HPushArgument* push_argument) {
HCall::SetArgumentAt(index + 1, push_argument);
}
DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call_keyed")
};
class HCallNamed: public HCall {
public:
HCallNamed(Handle<String> name, int argument_count)
: HCall(argument_count), name_(name) { }
virtual void PrintDataTo(StringStream* stream) const;
Handle<String> name() const { return name_; }
DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call_named")
private:
Handle<String> name_;
};
class HCallFunction: public HCall {
public:
explicit HCallFunction(int argument_count) : HCall(argument_count) { }
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call_function")
};
class HCallGlobal: public HCall {
public:
HCallGlobal(Handle<String> name, int argument_count)
: HCall(argument_count), name_(name) { }
virtual void PrintDataTo(StringStream* stream) const;
Handle<String> name() const { return name_; }
DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call_global")
private:
Handle<String> name_;
};
class HCallKnownGlobal: public HCall {
public:
HCallKnownGlobal(Handle<JSFunction> target,
int argument_count)
: HCall(argument_count), target_(target) { }
Handle<JSFunction> target() const { return target_; }
DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal, "call_known_global")
private:
Handle<JSFunction> target_;
};
class HCallNew: public HCall {
public:
explicit HCallNew(int argument_count) : HCall(argument_count) { }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
HValue* constructor() const { return ArgumentAt(0); }
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call_new")
};
class HCallRuntime: public HCall {
public:
HCallRuntime(Handle<String> name,
Runtime::Function* c_function,
int argument_count)
: HCall(argument_count), c_function_(c_function), name_(name) { }
virtual void PrintDataTo(StringStream* stream) const;
Runtime::Function* function() const { return c_function_; }
Handle<String> name() const { return name_; }
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call_runtime")
private:
Runtime::Function* c_function_;
Handle<String> name_;
};
class 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> 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> 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 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<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 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<JSObject> prototype, Handle<JSObject> holder)
: prototype_(prototype), holder_(holder) {
SetFlag(kUseGVN);
SetFlag(kDependsOnMaps);
}
virtual bool IsCheckInstruction() const { return true; }
#ifdef DEBUG
virtual void Verify() const;
#endif
Handle<JSObject> prototype() const { return prototype_; }
Handle<JSObject> holder() const { return holder_; }
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check_prototype_maps")
virtual intptr_t Hashcode() const {
ASSERT(!Heap::IsAllocationAllowed());
intptr_t hash = reinterpret_cast<intptr_t>(*prototype());
hash = 17 * hash + reinterpret_cast<intptr_t>(*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<JSObject> prototype_;
Handle<JSObject> 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<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_; }
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<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 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) {
// 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")
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<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_; }
protected:
virtual bool DataEquals(HValue* other) const {
HClassOfTest* b = HClassOfTest::cast(other);
return class_name_.is_identical_to(b->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 HInstanceOfKnownGlobal: public HUnaryOperation {
public:
HInstanceOfKnownGlobal(HValue* left, Handle<JSFunction> right)
: HUnaryOperation(left), function_(right) {
set_representation(Representation::Tagged());
SetFlagMask(AllSideEffects());
}
Handle<JSFunction> function() { return function_; }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal,
"instance_of_known_global")
private:
Handle<JSFunction> 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<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 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<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 HLoadFunctionPrototype: public HUnaryOperation {
public:
explicit HLoadFunctionPrototype(HValue* function)
: HUnaryOperation(function) {
set_representation(Representation::Tagged());
SetFlagMask(kDependsOnFunctionPrototypes);
}
HValue* function() const { return OperandAt(0); }
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::Tagged();
}
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load_function_prototype")
protected:
virtual bool DataEquals(HValue* other) const { return true; }
};
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<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); }
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<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); }
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 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_