v8/src/hydrogen-instructions.h
sgjesse@chromium.org 7311e10fdb Optimize instanceof further
If the instance of is performed against what is beliwed to be a constant global function inline the instance of check and have the call to the instanceof stub in deferred code. The inlined check will be patched by the instanceof stub when called from deferred code. This is indicated by the lithium instruction LInstanceOfKnownGlobal.

To help the patching the delta from the return address to the patch site is placed just below the return address in the edi slot of the pushad/popad ares. This is safe because the edi register (which is pushed last) is a temporary for the lithium instruction.

As the instanceof stub can call other JavaScript an additional marking for saving all double registers have been added.

Also tweaked the instanceof stub to produce true/false objects instead of 0/1 for the case with deferred code.
Review URL: http://codereview.chromium.org/5990005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6173 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2011-01-05 11:17:37 +00:00

3035 lines
83 KiB
C++

// 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
// HConstant
// HControlInstruction
// HDeoptimize
// HGoto
// HUnaryControlInstruction
// HBranch
// HCompareMapAndBranch
// HReturn
// HThrow
// HEnterInlined
// HFunctionLiteral
// HGlobalObject
// HGlobalReceiver
// HLeaveInlined
// HLoadGlobal
// HMaterializedLiteral
// HArrayLiteral
// HObjectLiteral
// HRegExpLiteral
// HOsrEntry
// HParameter
// HSimulate
// HStackCheck
// HStoreKeyed
// HStoreKeyedFastElement
// HStoreKeyedGeneric
// HUnaryOperation
// HBitNot
// HChange
// HCheckFunction
// HCheckInstanceType
// HCheckMap
// HCheckNonSmi
// HCheckPrototypeMaps
// 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(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
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 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_; }
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 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 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_