211a867943
Use corresponding phi from the loop entry as a hint to infer proper representation for HUnkownOSRValue and dependent phis. R=fschneider@chromium.org Review URL: https://chromiumcodereview.appspot.com/9704012 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11055 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
4831 lines
130 KiB
C++
4831 lines
130 KiB
C++
// Copyright 2012 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 "allocation.h"
|
|
#include "code-stubs.h"
|
|
#include "data-flow.h"
|
|
#include "small-pointer-list.h"
|
|
#include "string-stream.h"
|
|
#include "v8conversions.h"
|
|
#include "v8utils.h"
|
|
#include "zone.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
// Forward declarations.
|
|
class HBasicBlock;
|
|
class HEnvironment;
|
|
class HInstruction;
|
|
class HLoopInformation;
|
|
class HValue;
|
|
class LInstruction;
|
|
class LChunkBuilder;
|
|
|
|
|
|
#define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
|
|
V(BitwiseBinaryOperation) \
|
|
V(ControlInstruction) \
|
|
V(Instruction) \
|
|
|
|
|
|
#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
|
|
V(AbnormalExit) \
|
|
V(AccessArgumentsAt) \
|
|
V(Add) \
|
|
V(AllocateObject) \
|
|
V(ApplyArguments) \
|
|
V(ArgumentsElements) \
|
|
V(ArgumentsLength) \
|
|
V(ArgumentsObject) \
|
|
V(ArrayLiteral) \
|
|
V(Bitwise) \
|
|
V(BitNot) \
|
|
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(ClampToUint8) \
|
|
V(ClassOfTestAndBranch) \
|
|
V(CompareIDAndBranch) \
|
|
V(CompareGeneric) \
|
|
V(CompareObjectEqAndBranch) \
|
|
V(CompareMap) \
|
|
V(CompareConstantEqAndBranch) \
|
|
V(Constant) \
|
|
V(Context) \
|
|
V(DeclareGlobals) \
|
|
V(DeleteProperty) \
|
|
V(Deoptimize) \
|
|
V(Div) \
|
|
V(ElementsKind) \
|
|
V(EnterInlined) \
|
|
V(FastLiteral) \
|
|
V(FixedArrayBaseLength) \
|
|
V(ForceRepresentation) \
|
|
V(FunctionLiteral) \
|
|
V(GetCachedArrayIndex) \
|
|
V(GlobalObject) \
|
|
V(GlobalReceiver) \
|
|
V(Goto) \
|
|
V(HasCachedArrayIndexAndBranch) \
|
|
V(HasInstanceTypeAndBranch) \
|
|
V(In) \
|
|
V(InstanceOf) \
|
|
V(InstanceOfKnownGlobal) \
|
|
V(InvokeFunction) \
|
|
V(IsConstructCallAndBranch) \
|
|
V(IsNilAndBranch) \
|
|
V(IsObjectAndBranch) \
|
|
V(IsStringAndBranch) \
|
|
V(IsSmiAndBranch) \
|
|
V(IsUndetectableAndBranch) \
|
|
V(StringCompareAndBranch) \
|
|
V(JSArrayLength) \
|
|
V(LeaveInlined) \
|
|
V(LoadContextSlot) \
|
|
V(LoadElements) \
|
|
V(LoadExternalArrayPointer) \
|
|
V(LoadFunctionPrototype) \
|
|
V(LoadGlobalCell) \
|
|
V(LoadGlobalGeneric) \
|
|
V(LoadKeyedFastDoubleElement) \
|
|
V(LoadKeyedFastElement) \
|
|
V(LoadKeyedGeneric) \
|
|
V(LoadKeyedSpecializedArrayElement) \
|
|
V(LoadNamedField) \
|
|
V(LoadNamedFieldPolymorphic) \
|
|
V(LoadNamedGeneric) \
|
|
V(Mod) \
|
|
V(Mul) \
|
|
V(ObjectLiteral) \
|
|
V(OsrEntry) \
|
|
V(OuterContext) \
|
|
V(Parameter) \
|
|
V(Power) \
|
|
V(PushArgument) \
|
|
V(Random) \
|
|
V(RegExpLiteral) \
|
|
V(Return) \
|
|
V(Sar) \
|
|
V(Shl) \
|
|
V(Shr) \
|
|
V(Simulate) \
|
|
V(SoftDeoptimize) \
|
|
V(StackCheck) \
|
|
V(StoreContextSlot) \
|
|
V(StoreGlobalCell) \
|
|
V(StoreGlobalGeneric) \
|
|
V(StoreKeyedFastDoubleElement) \
|
|
V(StoreKeyedFastElement) \
|
|
V(StoreKeyedGeneric) \
|
|
V(StoreKeyedSpecializedArrayElement) \
|
|
V(StoreNamedField) \
|
|
V(StoreNamedGeneric) \
|
|
V(StringAdd) \
|
|
V(StringCharCodeAt) \
|
|
V(StringCharFromCode) \
|
|
V(StringLength) \
|
|
V(Sub) \
|
|
V(ThisFunction) \
|
|
V(Throw) \
|
|
V(ToFastProperties) \
|
|
V(TransitionElementsKind) \
|
|
V(Typeof) \
|
|
V(TypeofIsAndBranch) \
|
|
V(UnaryMathOperation) \
|
|
V(UnknownOSRValue) \
|
|
V(UseConst) \
|
|
V(ValueOf) \
|
|
V(ForInPrepareMap) \
|
|
V(ForInCacheArray) \
|
|
V(CheckMapValue) \
|
|
V(LoadFieldByIndex) \
|
|
V(DateField) \
|
|
V(WrapReceiver)
|
|
|
|
#define GVN_FLAG_LIST(V) \
|
|
V(Calls) \
|
|
V(InobjectFields) \
|
|
V(BackingStoreFields) \
|
|
V(ElementsKind) \
|
|
V(ElementsPointer) \
|
|
V(ArrayElements) \
|
|
V(DoubleArrayElements) \
|
|
V(SpecializedArrayElements) \
|
|
V(GlobalVars) \
|
|
V(Maps) \
|
|
V(ArrayLengths) \
|
|
V(ContextSlots) \
|
|
V(OsrEntries)
|
|
|
|
#define DECLARE_ABSTRACT_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); \
|
|
}
|
|
|
|
|
|
#define DECLARE_CONCRETE_INSTRUCTION(type) \
|
|
virtual LInstruction* CompileToLithium(LChunkBuilder* builder); \
|
|
static H##type* cast(HValue* value) { \
|
|
ASSERT(value->Is##type()); \
|
|
return reinterpret_cast<H##type*>(value); \
|
|
} \
|
|
virtual Opcode opcode() const { return HValue::k##type; }
|
|
|
|
|
|
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) { }
|
|
|
|
int32_t upper() const { return upper_; }
|
|
int32_t lower() const { return lower_; }
|
|
Range* next() const { return next_; }
|
|
Range* CopyClearLower(Zone* zone) const {
|
|
return new(zone) Range(kMinInt, upper_);
|
|
}
|
|
Range* CopyClearUpper(Zone* zone) const {
|
|
return new(zone) Range(lower_, kMaxInt);
|
|
}
|
|
Range* Copy(Zone* zone) const {
|
|
Range* result = new(zone) Range(lower_, upper_);
|
|
result->set_can_be_minus_zero(CanBeMinusZero());
|
|
return result;
|
|
}
|
|
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; }
|
|
bool IsMostGeneric() const {
|
|
return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
|
|
}
|
|
bool IsInSmiRange() const {
|
|
return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
|
|
}
|
|
void KeepOrder();
|
|
#ifdef DEBUG
|
|
void Verify() const;
|
|
#endif
|
|
|
|
void StackUpon(Range* other) {
|
|
Intersect(other);
|
|
next_ = other;
|
|
}
|
|
|
|
void Intersect(Range* other);
|
|
void Union(Range* other);
|
|
|
|
void AddConstant(int32_t value);
|
|
void Sar(int32_t value);
|
|
void Shl(int32_t value);
|
|
bool AddAndCheckOverflow(Range* other);
|
|
bool SubAndCheckOverflow(Range* other);
|
|
bool MulAndCheckOverflow(Range* other);
|
|
|
|
private:
|
|
int32_t lower_;
|
|
int32_t upper_;
|
|
Range* next_;
|
|
bool can_be_minus_zero_;
|
|
};
|
|
|
|
|
|
class Representation {
|
|
public:
|
|
enum Kind {
|
|
kNone,
|
|
kTagged,
|
|
kDouble,
|
|
kInteger32,
|
|
kExternal,
|
|
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); }
|
|
static Representation External() { return Representation(kExternal); }
|
|
|
|
bool Equals(const Representation& other) {
|
|
return kind_ == other.kind_;
|
|
}
|
|
|
|
Kind kind() const { return static_cast<Kind>(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 IsExternal() const { return kind_ == kExternal; }
|
|
bool IsSpecialization() const {
|
|
return kind_ == kInteger32 || kind_ == kDouble;
|
|
}
|
|
const char* Mnemonic() const;
|
|
|
|
private:
|
|
explicit Representation(Kind k) : kind_(k) { }
|
|
|
|
// Make sure kind fits in int8.
|
|
STATIC_ASSERT(kNumRepresentations <= (1 << kBitsPerByte));
|
|
|
|
int8_t 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;
|
|
}
|
|
|
|
bool IsHeapObject() {
|
|
ASSERT(type_ != kUninitialized);
|
|
return IsHeapNumber() || IsString() || IsNonPrimitive();
|
|
}
|
|
|
|
static HType TypeFromValue(Handle<Object> value);
|
|
|
|
const char* ToString();
|
|
|
|
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 0000 0001
|
|
kUninitialized = 0x1fff // 0001 1111 1111 1111
|
|
};
|
|
|
|
// Make sure type fits in int16.
|
|
STATIC_ASSERT(kUninitialized < (1 << (2 * kBitsPerByte)));
|
|
|
|
explicit HType(Type t) : type_(t) { }
|
|
|
|
int16_t type_;
|
|
};
|
|
|
|
|
|
class HUseListNode: public ZoneObject {
|
|
public:
|
|
HUseListNode(HValue* value, int index, HUseListNode* tail)
|
|
: tail_(tail), value_(value), index_(index) {
|
|
}
|
|
|
|
HUseListNode* tail();
|
|
HValue* value() const { return value_; }
|
|
int index() const { return index_; }
|
|
|
|
void set_tail(HUseListNode* list) { tail_ = list; }
|
|
|
|
#ifdef DEBUG
|
|
void Zap() {
|
|
tail_ = reinterpret_cast<HUseListNode*>(1);
|
|
value_ = NULL;
|
|
index_ = -1;
|
|
}
|
|
#endif
|
|
|
|
private:
|
|
HUseListNode* tail_;
|
|
HValue* value_;
|
|
int index_;
|
|
};
|
|
|
|
|
|
// We reuse use list nodes behind the scenes as uses are added and deleted.
|
|
// This class is the safe way to iterate uses while deleting them.
|
|
class HUseIterator BASE_EMBEDDED {
|
|
public:
|
|
bool Done() { return current_ == NULL; }
|
|
void Advance();
|
|
|
|
HValue* value() {
|
|
ASSERT(!Done());
|
|
return value_;
|
|
}
|
|
|
|
int index() {
|
|
ASSERT(!Done());
|
|
return index_;
|
|
}
|
|
|
|
private:
|
|
explicit HUseIterator(HUseListNode* head);
|
|
|
|
HUseListNode* current_;
|
|
HUseListNode* next_;
|
|
HValue* value_;
|
|
int index_;
|
|
|
|
friend class HValue;
|
|
};
|
|
|
|
|
|
// 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 GVNFlag {
|
|
// Declare global value numbering flags.
|
|
#define DECLARE_FLAG(type) kChanges##type, kDependsOn##type,
|
|
GVN_FLAG_LIST(DECLARE_FLAG)
|
|
#undef DECLARE_FLAG
|
|
kAfterLastFlag,
|
|
kLastFlag = kAfterLastFlag - 1
|
|
};
|
|
|
|
typedef EnumSet<GVNFlag> GVNFlagSet;
|
|
|
|
|
|
class HValue: public ZoneObject {
|
|
public:
|
|
static const int kNoNumber = -1;
|
|
|
|
enum Flag {
|
|
kFlexibleRepresentation,
|
|
// Participate in Global Value Numbering, i.e. elimination of
|
|
// unnecessary recomputations. If an instruction sets this flag, it must
|
|
// implement DataEquals(), which will be used to determine if other
|
|
// occurrences of the instruction are indeed the same.
|
|
kUseGVN,
|
|
kCanOverflow,
|
|
kBailoutOnMinusZero,
|
|
kCanBeDivByZero,
|
|
kDeoptimizeOnUndefined,
|
|
kIsArguments,
|
|
kTruncatingToInt32,
|
|
kIsDead,
|
|
kLastFlag = kIsDead
|
|
};
|
|
|
|
STATIC_ASSERT(kLastFlag < kBitsPerInt);
|
|
|
|
static const int kChangesToDependsFlagsLeftShift = 1;
|
|
|
|
static GVNFlagSet ConvertChangesToDependsFlags(GVNFlagSet flags) {
|
|
return GVNFlagSet(flags.ToIntegral() << kChangesToDependsFlagsLeftShift);
|
|
}
|
|
|
|
static HValue* cast(HValue* value) { return value; }
|
|
|
|
enum Opcode {
|
|
// Declare a unique enum value for each hydrogen instruction.
|
|
#define DECLARE_OPCODE(type) k##type,
|
|
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
|
|
kPhi
|
|
#undef DECLARE_OPCODE
|
|
};
|
|
virtual Opcode opcode() const = 0;
|
|
|
|
// Declare a non-virtual predicates for each concrete HInstruction or HValue.
|
|
#define DECLARE_PREDICATE(type) \
|
|
bool Is##type() const { return opcode() == k##type; }
|
|
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
|
|
#undef DECLARE_PREDICATE
|
|
bool IsPhi() const { return opcode() == kPhi; }
|
|
|
|
// Declare virtual predicates for abstract HInstruction or HValue
|
|
#define DECLARE_PREDICATE(type) \
|
|
virtual bool Is##type() const { return false; }
|
|
HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
|
|
#undef DECLARE_PREDICATE
|
|
|
|
HValue() : block_(NULL),
|
|
id_(kNoNumber),
|
|
type_(HType::Tagged()),
|
|
use_list_(NULL),
|
|
range_(NULL),
|
|
flags_(0) {}
|
|
virtual ~HValue() {}
|
|
|
|
HBasicBlock* block() const { return block_; }
|
|
void SetBlock(HBasicBlock* block);
|
|
int LoopWeight() const;
|
|
|
|
int id() const { return id_; }
|
|
void set_id(int id) { id_ = id; }
|
|
|
|
HUseIterator uses() const { return HUseIterator(use_list_); }
|
|
|
|
virtual bool EmitAtUses() { return false; }
|
|
Representation representation() const { return representation_; }
|
|
void ChangeRepresentation(Representation r) {
|
|
// Representation was already set and is allowed to be changed.
|
|
ASSERT(!r.IsNone());
|
|
ASSERT(CheckFlag(kFlexibleRepresentation));
|
|
RepresentationChanged(r);
|
|
representation_ = r;
|
|
}
|
|
void AssumeRepresentation(Representation r);
|
|
|
|
virtual bool IsConvertibleToInteger() const { return true; }
|
|
|
|
HType type() const { return type_; }
|
|
void set_type(HType new_type) {
|
|
ASSERT(new_type.IsSubtypeOf(type_));
|
|
type_ = new_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 three operations that need to propagate back to more than
|
|
// one input. They are phi and binary div and mul. They always return NULL
|
|
// and expect the caller to take care of things.
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited) {
|
|
visited->Add(id());
|
|
return NULL;
|
|
}
|
|
|
|
bool IsDefinedAfter(HBasicBlock* other) const;
|
|
|
|
// Operands.
|
|
virtual int OperandCount() = 0;
|
|
virtual HValue* OperandAt(int index) = 0;
|
|
void SetOperandAt(int index, HValue* value);
|
|
|
|
void DeleteAndReplaceWith(HValue* other);
|
|
void ReplaceAllUsesWith(HValue* other);
|
|
bool HasNoUses() const { return use_list_ == NULL; }
|
|
bool HasMultipleUses() const {
|
|
return use_list_ != NULL && use_list_->tail() != NULL;
|
|
}
|
|
int UseCount() const;
|
|
|
|
// Mark this HValue as dead and to be removed from other HValues' use lists.
|
|
void Kill();
|
|
|
|
int flags() const { return flags_; }
|
|
void SetFlag(Flag f) { flags_ |= (1 << f); }
|
|
void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
|
|
bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
|
|
|
|
// Returns true if the flag specified is set for all uses, false otherwise.
|
|
bool CheckUsesForFlag(Flag f);
|
|
|
|
GVNFlagSet gvn_flags() const { return gvn_flags_; }
|
|
void SetGVNFlag(GVNFlag f) { gvn_flags_.Add(f); }
|
|
void ClearGVNFlag(GVNFlag f) { gvn_flags_.Remove(f); }
|
|
bool CheckGVNFlag(GVNFlag f) const { return gvn_flags_.Contains(f); }
|
|
void SetAllSideEffects() { gvn_flags_.Add(AllSideEffectsFlagSet()); }
|
|
void ClearAllSideEffects() {
|
|
gvn_flags_.Remove(AllSideEffectsFlagSet());
|
|
}
|
|
bool HasSideEffects() const {
|
|
return gvn_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
|
|
}
|
|
bool HasObservableSideEffects() const {
|
|
return gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
|
|
}
|
|
|
|
GVNFlagSet DependsOnFlags() const {
|
|
GVNFlagSet result = gvn_flags_;
|
|
result.Intersect(AllDependsOnFlagSet());
|
|
return result;
|
|
}
|
|
|
|
GVNFlagSet SideEffectFlags() const {
|
|
GVNFlagSet result = gvn_flags_;
|
|
result.Intersect(AllSideEffectsFlagSet());
|
|
return result;
|
|
}
|
|
|
|
GVNFlagSet ChangesFlags() const {
|
|
GVNFlagSet result = gvn_flags_;
|
|
result.Intersect(AllChangesFlagSet());
|
|
return result;
|
|
}
|
|
|
|
GVNFlagSet ObservableChangesFlags() const {
|
|
GVNFlagSet result = gvn_flags_;
|
|
result.Intersect(AllChangesFlagSet());
|
|
result.Intersect(AllObservableSideEffectsFlagSet());
|
|
return result;
|
|
}
|
|
|
|
Range* range() const { return range_; }
|
|
bool HasRange() const { return range_ != NULL; }
|
|
void AddNewRange(Range* r, Zone* zone);
|
|
void RemoveLastAddedRange();
|
|
void ComputeInitialRange(Zone* zone);
|
|
|
|
// Representation helpers.
|
|
virtual Representation RequiredInputRepresentation(int index) = 0;
|
|
|
|
virtual Representation InferredRepresentation() {
|
|
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; }
|
|
|
|
bool Equals(HValue* other);
|
|
virtual intptr_t Hashcode();
|
|
|
|
// Printing support.
|
|
virtual void PrintTo(StringStream* stream) = 0;
|
|
void PrintNameTo(StringStream* stream);
|
|
void PrintTypeTo(StringStream* stream);
|
|
void PrintRangeTo(StringStream* stream);
|
|
void PrintChangesTo(StringStream* stream);
|
|
|
|
const char* Mnemonic() const;
|
|
|
|
// Updated the inferred type of this instruction and returns true if
|
|
// it has changed.
|
|
bool UpdateInferredType();
|
|
|
|
virtual HType CalculateInferredType();
|
|
|
|
#ifdef DEBUG
|
|
virtual void Verify() = 0;
|
|
#endif
|
|
|
|
protected:
|
|
// This function must be overridden for instructions with flag kUseGVN, to
|
|
// compare the non-Operand parts of the instruction.
|
|
virtual bool DataEquals(HValue* other) {
|
|
UNREACHABLE();
|
|
return false;
|
|
}
|
|
virtual void RepresentationChanged(Representation to) { }
|
|
virtual Range* InferRange(Zone* zone);
|
|
virtual void DeleteFromGraph() = 0;
|
|
virtual void InternalSetOperandAt(int index, HValue* value) = 0;
|
|
void clear_block() {
|
|
ASSERT(block_ != NULL);
|
|
block_ = NULL;
|
|
}
|
|
|
|
void set_representation(Representation r) {
|
|
// Representation is set-once.
|
|
ASSERT(representation_.IsNone() && !r.IsNone());
|
|
representation_ = r;
|
|
}
|
|
|
|
static GVNFlagSet AllDependsOnFlagSet() {
|
|
GVNFlagSet result;
|
|
// Create changes mask.
|
|
#define ADD_FLAG(type) result.Add(kDependsOn##type);
|
|
GVN_FLAG_LIST(ADD_FLAG)
|
|
#undef ADD_FLAG
|
|
return result;
|
|
}
|
|
|
|
static GVNFlagSet AllChangesFlagSet() {
|
|
GVNFlagSet result;
|
|
// Create changes mask.
|
|
#define ADD_FLAG(type) result.Add(kChanges##type);
|
|
GVN_FLAG_LIST(ADD_FLAG)
|
|
#undef ADD_FLAG
|
|
return result;
|
|
}
|
|
|
|
// A flag mask to mark an instruction as having arbitrary side effects.
|
|
static GVNFlagSet AllSideEffectsFlagSet() {
|
|
GVNFlagSet result = AllChangesFlagSet();
|
|
result.Remove(kChangesOsrEntries);
|
|
return result;
|
|
}
|
|
|
|
// A flag mask of all side effects that can make observable changes in
|
|
// an executing program (i.e. are not safe to repeat, move or remove);
|
|
static GVNFlagSet AllObservableSideEffectsFlagSet() {
|
|
GVNFlagSet result = AllChangesFlagSet();
|
|
result.Remove(kChangesElementsKind);
|
|
result.Remove(kChangesElementsPointer);
|
|
result.Remove(kChangesMaps);
|
|
return result;
|
|
}
|
|
|
|
// Remove the matching use from the use list if present. Returns the
|
|
// removed list node or NULL.
|
|
HUseListNode* RemoveUse(HValue* value, int index);
|
|
|
|
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_;
|
|
HType type_;
|
|
HUseListNode* use_list_;
|
|
Range* range_;
|
|
int flags_;
|
|
GVNFlagSet gvn_flags_;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(HValue);
|
|
};
|
|
|
|
|
|
class HInstruction: public HValue {
|
|
public:
|
|
HInstruction* next() const { return next_; }
|
|
HInstruction* previous() const { return previous_; }
|
|
|
|
virtual void PrintTo(StringStream* stream);
|
|
virtual void PrintDataTo(StringStream* stream) { }
|
|
|
|
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; }
|
|
|
|
bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
|
|
|
|
virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
|
|
|
|
#ifdef DEBUG
|
|
virtual void Verify();
|
|
#endif
|
|
|
|
virtual bool IsCall() { return false; }
|
|
|
|
DECLARE_ABSTRACT_INSTRUCTION(Instruction)
|
|
|
|
protected:
|
|
HInstruction()
|
|
: next_(NULL),
|
|
previous_(NULL),
|
|
position_(RelocInfo::kNoPosition) {
|
|
SetGVNFlag(kDependsOnOsrEntries);
|
|
}
|
|
|
|
virtual void DeleteFromGraph() { Unlink(); }
|
|
|
|
private:
|
|
void InitializeAsFirst(HBasicBlock* block) {
|
|
ASSERT(!IsLinked());
|
|
SetBlock(block);
|
|
}
|
|
|
|
void PrintMnemonicTo(StringStream* stream);
|
|
|
|
HInstruction* next_;
|
|
HInstruction* previous_;
|
|
int position_;
|
|
|
|
friend class HBasicBlock;
|
|
};
|
|
|
|
|
|
template<int V>
|
|
class HTemplateInstruction : public HInstruction {
|
|
public:
|
|
int OperandCount() { return V; }
|
|
HValue* OperandAt(int i) { return inputs_[i]; }
|
|
|
|
protected:
|
|
void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; }
|
|
|
|
private:
|
|
EmbeddedContainer<HValue*, V> inputs_;
|
|
};
|
|
|
|
|
|
class HControlInstruction: public HInstruction {
|
|
public:
|
|
virtual HBasicBlock* SuccessorAt(int i) = 0;
|
|
virtual int SuccessorCount() = 0;
|
|
virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0;
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
HBasicBlock* FirstSuccessor() {
|
|
return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
|
|
}
|
|
HBasicBlock* SecondSuccessor() {
|
|
return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
|
|
}
|
|
|
|
DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction)
|
|
};
|
|
|
|
|
|
class HSuccessorIterator BASE_EMBEDDED {
|
|
public:
|
|
explicit HSuccessorIterator(HControlInstruction* instr)
|
|
: instr_(instr), current_(0) { }
|
|
|
|
bool Done() { return current_ >= instr_->SuccessorCount(); }
|
|
HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
|
|
void Advance() { current_++; }
|
|
|
|
private:
|
|
HControlInstruction* instr_;
|
|
int current_;
|
|
};
|
|
|
|
|
|
template<int S, int V>
|
|
class HTemplateControlInstruction: public HControlInstruction {
|
|
public:
|
|
int SuccessorCount() { return S; }
|
|
HBasicBlock* SuccessorAt(int i) { return successors_[i]; }
|
|
void SetSuccessorAt(int i, HBasicBlock* block) { successors_[i] = block; }
|
|
|
|
int OperandCount() { return V; }
|
|
HValue* OperandAt(int i) { return inputs_[i]; }
|
|
|
|
|
|
protected:
|
|
void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; }
|
|
|
|
private:
|
|
EmbeddedContainer<HBasicBlock*, S> successors_;
|
|
EmbeddedContainer<HValue*, V> inputs_;
|
|
};
|
|
|
|
|
|
class HBlockEntry: public HTemplateInstruction<0> {
|
|
public:
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(BlockEntry)
|
|
};
|
|
|
|
|
|
// We insert soft-deoptimize when we hit code with unknown typefeedback,
|
|
// so that we get a chance of re-optimizing with useful typefeedback.
|
|
// HSoftDeoptimize does not end a basic block as opposed to HDeoptimize.
|
|
class HSoftDeoptimize: public HTemplateInstruction<0> {
|
|
public:
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(SoftDeoptimize)
|
|
};
|
|
|
|
|
|
class HDeoptimize: public HControlInstruction {
|
|
public:
|
|
explicit HDeoptimize(int environment_length) : values_(environment_length) { }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
virtual int OperandCount() { return values_.length(); }
|
|
virtual HValue* OperandAt(int index) { return values_[index]; }
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual int SuccessorCount() { return 0; }
|
|
virtual HBasicBlock* SuccessorAt(int i) {
|
|
UNREACHABLE();
|
|
return NULL;
|
|
}
|
|
virtual void SetSuccessorAt(int i, HBasicBlock* block) {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
void AddEnvironmentValue(HValue* value) {
|
|
values_.Add(NULL);
|
|
SetOperandAt(values_.length() - 1, value);
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
|
|
|
|
enum UseEnvironment {
|
|
kNoUses,
|
|
kUseAll
|
|
};
|
|
|
|
protected:
|
|
virtual void InternalSetOperandAt(int index, HValue* value) {
|
|
values_[index] = value;
|
|
}
|
|
|
|
private:
|
|
ZoneList<HValue*> values_;
|
|
};
|
|
|
|
|
|
class HGoto: public HTemplateControlInstruction<1, 0> {
|
|
public:
|
|
explicit HGoto(HBasicBlock* target) {
|
|
SetSuccessorAt(0, target);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Goto)
|
|
};
|
|
|
|
|
|
class HUnaryControlInstruction: public HTemplateControlInstruction<2, 1> {
|
|
public:
|
|
HUnaryControlInstruction(HValue* value,
|
|
HBasicBlock* true_target,
|
|
HBasicBlock* false_target) {
|
|
SetOperandAt(0, value);
|
|
SetSuccessorAt(0, true_target);
|
|
SetSuccessorAt(1, false_target);
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
HValue* value() { return OperandAt(0); }
|
|
};
|
|
|
|
|
|
class HBranch: public HUnaryControlInstruction {
|
|
public:
|
|
HBranch(HValue* value,
|
|
HBasicBlock* true_target,
|
|
HBasicBlock* false_target,
|
|
ToBooleanStub::Types expected_input_types = ToBooleanStub::no_types())
|
|
: HUnaryControlInstruction(value, true_target, false_target),
|
|
expected_input_types_(expected_input_types) {
|
|
ASSERT(true_target != NULL && false_target != NULL);
|
|
}
|
|
explicit HBranch(HValue* value)
|
|
: HUnaryControlInstruction(value, NULL, NULL) { }
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
ToBooleanStub::Types expected_input_types() const {
|
|
return expected_input_types_;
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Branch)
|
|
|
|
private:
|
|
ToBooleanStub::Types expected_input_types_;
|
|
};
|
|
|
|
|
|
class HCompareMap: public HUnaryControlInstruction {
|
|
public:
|
|
HCompareMap(HValue* value,
|
|
Handle<Map> map,
|
|
HBasicBlock* true_target,
|
|
HBasicBlock* false_target)
|
|
: HUnaryControlInstruction(value, true_target, false_target),
|
|
map_(map) {
|
|
ASSERT(true_target != NULL);
|
|
ASSERT(false_target != NULL);
|
|
ASSERT(!map.is_null());
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
Handle<Map> map() const { return map_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CompareMap)
|
|
|
|
private:
|
|
Handle<Map> map_;
|
|
};
|
|
|
|
|
|
class HReturn: public HTemplateControlInstruction<0, 1> {
|
|
public:
|
|
explicit HReturn(HValue* value) {
|
|
SetOperandAt(0, value);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
HValue* value() { return OperandAt(0); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Return)
|
|
};
|
|
|
|
|
|
class HAbnormalExit: public HTemplateControlInstruction<0, 0> {
|
|
public:
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
|
|
};
|
|
|
|
|
|
class HUnaryOperation: public HTemplateInstruction<1> {
|
|
public:
|
|
explicit HUnaryOperation(HValue* value) {
|
|
SetOperandAt(0, value);
|
|
}
|
|
|
|
static HUnaryOperation* cast(HValue* value) {
|
|
return reinterpret_cast<HUnaryOperation*>(value);
|
|
}
|
|
|
|
HValue* value() { return OperandAt(0); }
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
};
|
|
|
|
|
|
class HThrow: public HTemplateInstruction<2> {
|
|
public:
|
|
HThrow(HValue* context, HValue* value) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, value);
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* value() { return OperandAt(1); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Throw)
|
|
};
|
|
|
|
|
|
class HUseConst: public HUnaryOperation {
|
|
public:
|
|
explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(UseConst)
|
|
};
|
|
|
|
|
|
class HForceRepresentation: public HTemplateInstruction<1> {
|
|
public:
|
|
HForceRepresentation(HValue* value, Representation required_representation) {
|
|
SetOperandAt(0, value);
|
|
set_representation(required_representation);
|
|
}
|
|
|
|
HValue* value() { return OperandAt(0); }
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return representation(); // Same as the output representation.
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
|
|
};
|
|
|
|
|
|
class HChange: public HUnaryOperation {
|
|
public:
|
|
HChange(HValue* value,
|
|
Representation to,
|
|
bool is_truncating,
|
|
bool deoptimize_on_undefined)
|
|
: HUnaryOperation(value) {
|
|
ASSERT(!value->representation().IsNone() && !to.IsNone());
|
|
ASSERT(!value->representation().Equals(to));
|
|
set_representation(to);
|
|
set_type(HType::TaggedNumber());
|
|
SetFlag(kUseGVN);
|
|
if (deoptimize_on_undefined) SetFlag(kDeoptimizeOnUndefined);
|
|
if (is_truncating) SetFlag(kTruncatingToInt32);
|
|
}
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
virtual HType CalculateInferredType();
|
|
virtual HValue* Canonicalize();
|
|
|
|
Representation from() { return value()->representation(); }
|
|
Representation to() { return representation(); }
|
|
bool deoptimize_on_undefined() const {
|
|
return CheckFlag(kDeoptimizeOnUndefined);
|
|
}
|
|
bool deoptimize_on_minus_zero() const {
|
|
return CheckFlag(kBailoutOnMinusZero);
|
|
}
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return from();
|
|
}
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Change)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HClampToUint8: public HUnaryOperation {
|
|
public:
|
|
explicit HClampToUint8(HValue* value)
|
|
: HUnaryOperation(value) {
|
|
set_representation(Representation::Integer32());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HSimulate: public HInstruction {
|
|
public:
|
|
HSimulate(int ast_id, int pop_count)
|
|
: ast_id_(ast_id),
|
|
pop_count_(pop_count),
|
|
values_(2),
|
|
assigned_indexes_(2) {}
|
|
virtual ~HSimulate() {}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
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 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() { return values_.length(); }
|
|
virtual HValue* OperandAt(int index) { return values_[index]; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Simulate)
|
|
|
|
#ifdef DEBUG
|
|
virtual void Verify();
|
|
#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_;
|
|
ZoneList<HValue*> values_;
|
|
ZoneList<int> assigned_indexes_;
|
|
};
|
|
|
|
|
|
class HStackCheck: public HTemplateInstruction<1> {
|
|
public:
|
|
enum Type {
|
|
kFunctionEntry,
|
|
kBackwardsBranch
|
|
};
|
|
|
|
HStackCheck(HValue* context, Type type) : type_(type) {
|
|
SetOperandAt(0, context);
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
void Eliminate() {
|
|
// The stack check eliminator might try to eliminate the same stack
|
|
// check instruction multiple times.
|
|
if (IsLinked()) {
|
|
DeleteFromGraph();
|
|
}
|
|
}
|
|
|
|
bool is_function_entry() { return type_ == kFunctionEntry; }
|
|
bool is_backwards_branch() { return type_ == kBackwardsBranch; }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StackCheck)
|
|
|
|
private:
|
|
Type type_;
|
|
};
|
|
|
|
|
|
class HEnterInlined: public HTemplateInstruction<0> {
|
|
public:
|
|
HEnterInlined(Handle<JSFunction> closure,
|
|
int arguments_count,
|
|
FunctionLiteral* function,
|
|
CallKind call_kind,
|
|
bool is_construct)
|
|
: closure_(closure),
|
|
arguments_count_(arguments_count),
|
|
function_(function),
|
|
call_kind_(call_kind),
|
|
is_construct_(is_construct) {
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
Handle<JSFunction> closure() const { return closure_; }
|
|
int arguments_count() const { return arguments_count_; }
|
|
FunctionLiteral* function() const { return function_; }
|
|
CallKind call_kind() const { return call_kind_; }
|
|
bool is_construct() const { return is_construct_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
|
|
|
|
private:
|
|
Handle<JSFunction> closure_;
|
|
int arguments_count_;
|
|
FunctionLiteral* function_;
|
|
CallKind call_kind_;
|
|
bool is_construct_;
|
|
};
|
|
|
|
|
|
class HLeaveInlined: public HTemplateInstruction<0> {
|
|
public:
|
|
HLeaveInlined() {}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
|
|
};
|
|
|
|
|
|
class HPushArgument: public HUnaryOperation {
|
|
public:
|
|
explicit HPushArgument(HValue* value) : HUnaryOperation(value) {
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* argument() { return OperandAt(0); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(PushArgument)
|
|
};
|
|
|
|
|
|
class HThisFunction: public HTemplateInstruction<0> {
|
|
public:
|
|
explicit HThisFunction(Handle<JSFunction> closure) : closure_(closure) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
Handle<JSFunction> closure() const { return closure_; }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
HThisFunction* b = HThisFunction::cast(other);
|
|
return *closure() == *b->closure();
|
|
}
|
|
|
|
private:
|
|
Handle<JSFunction> closure_;
|
|
};
|
|
|
|
|
|
class HContext: public HTemplateInstruction<0> {
|
|
public:
|
|
HContext() {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Context)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HOuterContext: public HUnaryOperation {
|
|
public:
|
|
explicit HOuterContext(HValue* inner) : HUnaryOperation(inner) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(OuterContext);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HDeclareGlobals: public HUnaryOperation {
|
|
public:
|
|
HDeclareGlobals(HValue* context,
|
|
Handle<FixedArray> pairs,
|
|
int flags)
|
|
: HUnaryOperation(context),
|
|
pairs_(pairs),
|
|
flags_(flags) {
|
|
set_representation(Representation::Tagged());
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
Handle<FixedArray> pairs() const { return pairs_; }
|
|
int flags() const { return flags_; }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
private:
|
|
Handle<FixedArray> pairs_;
|
|
int flags_;
|
|
};
|
|
|
|
|
|
class HGlobalObject: public HUnaryOperation {
|
|
public:
|
|
explicit HGlobalObject(HValue* context) : HUnaryOperation(context) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(GlobalObject)
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HGlobalReceiver: public HUnaryOperation {
|
|
public:
|
|
explicit HGlobalReceiver(HValue* global_object)
|
|
: HUnaryOperation(global_object) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver)
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
template <int V>
|
|
class HCall: public HTemplateInstruction<V> {
|
|
public:
|
|
// The argument count includes the receiver.
|
|
explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
|
|
this->set_representation(Representation::Tagged());
|
|
this->SetAllSideEffects();
|
|
}
|
|
|
|
virtual HType CalculateInferredType() { return HType::Tagged(); }
|
|
|
|
virtual int argument_count() const { return argument_count_; }
|
|
|
|
virtual bool IsCall() { return true; }
|
|
|
|
private:
|
|
int argument_count_;
|
|
};
|
|
|
|
|
|
class HUnaryCall: public HCall<1> {
|
|
public:
|
|
HUnaryCall(HValue* value, int argument_count)
|
|
: HCall<1>(argument_count) {
|
|
SetOperandAt(0, value);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
HValue* value() { return OperandAt(0); }
|
|
};
|
|
|
|
|
|
class HBinaryCall: public HCall<2> {
|
|
public:
|
|
HBinaryCall(HValue* first, HValue* second, int argument_count)
|
|
: HCall<2>(argument_count) {
|
|
SetOperandAt(0, first);
|
|
SetOperandAt(1, second);
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* first() { return OperandAt(0); }
|
|
HValue* second() { return OperandAt(1); }
|
|
};
|
|
|
|
|
|
class HInvokeFunction: public HBinaryCall {
|
|
public:
|
|
HInvokeFunction(HValue* context, HValue* function, int argument_count)
|
|
: HBinaryCall(context, function, argument_count) {
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* context() { return first(); }
|
|
HValue* function() { return second(); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
|
|
};
|
|
|
|
|
|
class HCallConstantFunction: public HCall<0> {
|
|
public:
|
|
HCallConstantFunction(Handle<JSFunction> function, int argument_count)
|
|
: HCall<0>(argument_count), function_(function) { }
|
|
|
|
Handle<JSFunction> function() const { return function_; }
|
|
|
|
bool IsApplyFunction() const {
|
|
return function_->code() ==
|
|
Isolate::Current()->builtins()->builtin(Builtins::kFunctionApply);
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction)
|
|
|
|
private:
|
|
Handle<JSFunction> function_;
|
|
};
|
|
|
|
|
|
class HCallKeyed: public HBinaryCall {
|
|
public:
|
|
HCallKeyed(HValue* context, HValue* key, int argument_count)
|
|
: HBinaryCall(context, key, argument_count) {
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* context() { return first(); }
|
|
HValue* key() { return second(); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallKeyed)
|
|
};
|
|
|
|
|
|
class HCallNamed: public HUnaryCall {
|
|
public:
|
|
HCallNamed(HValue* context, Handle<String> name, int argument_count)
|
|
: HUnaryCall(context, argument_count), name_(name) {
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
HValue* context() { return value(); }
|
|
Handle<String> name() const { return name_; }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallNamed)
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
private:
|
|
Handle<String> name_;
|
|
};
|
|
|
|
|
|
class HCallFunction: public HBinaryCall {
|
|
public:
|
|
HCallFunction(HValue* context, HValue* function, int argument_count)
|
|
: HBinaryCall(context, function, argument_count) {
|
|
}
|
|
|
|
HValue* context() { return first(); }
|
|
HValue* function() { return second(); }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallFunction)
|
|
};
|
|
|
|
|
|
class HCallGlobal: public HUnaryCall {
|
|
public:
|
|
HCallGlobal(HValue* context, Handle<String> name, int argument_count)
|
|
: HUnaryCall(context, argument_count), name_(name) {
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
HValue* context() { return value(); }
|
|
Handle<String> name() const { return name_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallGlobal)
|
|
|
|
private:
|
|
Handle<String> name_;
|
|
};
|
|
|
|
|
|
class HCallKnownGlobal: public HCall<0> {
|
|
public:
|
|
HCallKnownGlobal(Handle<JSFunction> target, int argument_count)
|
|
: HCall<0>(argument_count), target_(target) { }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
Handle<JSFunction> target() const { return target_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal)
|
|
|
|
private:
|
|
Handle<JSFunction> target_;
|
|
};
|
|
|
|
|
|
class HCallNew: public HBinaryCall {
|
|
public:
|
|
HCallNew(HValue* context, HValue* constructor, int argument_count)
|
|
: HBinaryCall(context, constructor, argument_count) {
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* context() { return first(); }
|
|
HValue* constructor() { return second(); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallNew)
|
|
};
|
|
|
|
|
|
class HCallRuntime: public HCall<1> {
|
|
public:
|
|
HCallRuntime(HValue* context,
|
|
Handle<String> name,
|
|
const Runtime::Function* c_function,
|
|
int argument_count)
|
|
: HCall<1>(argument_count), c_function_(c_function), name_(name) {
|
|
SetOperandAt(0, context);
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
const Runtime::Function* function() const { return c_function_; }
|
|
Handle<String> name() const { return name_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
|
|
|
|
private:
|
|
const Runtime::Function* c_function_;
|
|
Handle<String> name_;
|
|
};
|
|
|
|
|
|
class HJSArrayLength: public HTemplateInstruction<2> {
|
|
public:
|
|
HJSArrayLength(HValue* value, HValue* typecheck) {
|
|
// 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.
|
|
SetOperandAt(0, value);
|
|
SetOperandAt(1, typecheck);
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnArrayLengths);
|
|
SetGVNFlag(kDependsOnMaps);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
HValue* value() { return OperandAt(0); }
|
|
HValue* typecheck() { return OperandAt(1); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HFixedArrayBaseLength: public HUnaryOperation {
|
|
public:
|
|
explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnArrayLengths);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(FixedArrayBaseLength)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HElementsKind: public HUnaryOperation {
|
|
public:
|
|
explicit HElementsKind(HValue* value) : HUnaryOperation(value) {
|
|
set_representation(Representation::Integer32());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnElementsKind);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ElementsKind)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HBitNot: public HUnaryOperation {
|
|
public:
|
|
explicit HBitNot(HValue* value) : HUnaryOperation(value) {
|
|
set_representation(Representation::Integer32());
|
|
SetFlag(kUseGVN);
|
|
SetFlag(kTruncatingToInt32);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Integer32();
|
|
}
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(BitNot)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HUnaryMathOperation: public HTemplateInstruction<2> {
|
|
public:
|
|
HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
|
|
: op_(op) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, value);
|
|
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:
|
|
case kMathTan:
|
|
set_representation(Representation::Double());
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* value() { return OperandAt(1); }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual HType CalculateInferredType();
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
if (index == 0) {
|
|
return Representation::Tagged();
|
|
} else {
|
|
switch (op_) {
|
|
case kMathFloor:
|
|
case kMathRound:
|
|
case kMathCeil:
|
|
case kMathSqrt:
|
|
case kMathPowHalf:
|
|
case kMathLog:
|
|
case kMathSin:
|
|
case kMathCos:
|
|
case kMathTan:
|
|
return Representation::Double();
|
|
case kMathAbs:
|
|
return representation();
|
|
default:
|
|
UNREACHABLE();
|
|
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)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
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);
|
|
SetGVNFlag(kDependsOnElementsPointer);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadElements)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HLoadExternalArrayPointer: public HUnaryOperation {
|
|
public:
|
|
explicit HLoadExternalArrayPointer(HValue* value)
|
|
: HUnaryOperation(value) {
|
|
set_representation(Representation::External());
|
|
// The result of this instruction is idempotent as long as its inputs don't
|
|
// change. The external array of a specialized array elements object cannot
|
|
// change once set, so it's no necessary to introduce any additional
|
|
// dependencies on top of the inputs.
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HCheckMap: public HTemplateInstruction<2> {
|
|
public:
|
|
HCheckMap(HValue* value,
|
|
Handle<Map> map,
|
|
HValue* typecheck = NULL,
|
|
CompareMapMode mode = REQUIRE_EXACT_MAP)
|
|
: map_(map),
|
|
mode_(mode) {
|
|
SetOperandAt(0, value);
|
|
// If callers don't depend on a typecheck, they can pass in NULL. In that
|
|
// case we use a copy of the |value| argument as a dummy value.
|
|
SetOperandAt(1, typecheck != NULL ? typecheck : value);
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnMaps);
|
|
// If the map to check doesn't have the untransitioned elements, it must not
|
|
// be hoisted above TransitionElements instructions.
|
|
if (mode == REQUIRE_EXACT_MAP || !map->has_fast_smi_only_elements()) {
|
|
SetGVNFlag(kDependsOnElementsKind);
|
|
}
|
|
has_element_transitions_ =
|
|
map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL) != NULL ||
|
|
map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL) != NULL;
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
virtual HType CalculateInferredType();
|
|
|
|
HValue* value() { return OperandAt(0); }
|
|
Handle<Map> map() const { return map_; }
|
|
CompareMapMode mode() const { return mode_; }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckMap)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
HCheckMap* b = HCheckMap::cast(other);
|
|
// Two CheckMaps instructions are DataEqual if their maps are identical and
|
|
// they have the same mode. The mode comparison can be ignored if the map
|
|
// has no elements transitions.
|
|
return map_.is_identical_to(b->map()) &&
|
|
(b->mode() == mode() || !has_element_transitions_);
|
|
}
|
|
|
|
private:
|
|
bool has_element_transitions_;
|
|
Handle<Map> map_;
|
|
CompareMapMode mode_;
|
|
};
|
|
|
|
|
|
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) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
virtual HType CalculateInferredType();
|
|
|
|
#ifdef DEBUG
|
|
virtual void Verify();
|
|
#endif
|
|
|
|
Handle<JSFunction> target() const { return target_; }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckFunction)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
HCheckFunction* b = HCheckFunction::cast(other);
|
|
return target_.is_identical_to(b->target());
|
|
}
|
|
|
|
private:
|
|
Handle<JSFunction> target_;
|
|
};
|
|
|
|
|
|
class HCheckInstanceType: public HUnaryOperation {
|
|
public:
|
|
static HCheckInstanceType* NewIsSpecObject(HValue* value) {
|
|
return new HCheckInstanceType(value, IS_SPEC_OBJECT);
|
|
}
|
|
static HCheckInstanceType* NewIsJSArray(HValue* value) {
|
|
return new HCheckInstanceType(value, IS_JS_ARRAY);
|
|
}
|
|
static HCheckInstanceType* NewIsString(HValue* value) {
|
|
return new HCheckInstanceType(value, IS_STRING);
|
|
}
|
|
static HCheckInstanceType* NewIsSymbol(HValue* value) {
|
|
return new HCheckInstanceType(value, IS_SYMBOL);
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual HValue* Canonicalize();
|
|
|
|
bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
|
|
void GetCheckInterval(InstanceType* first, InstanceType* last);
|
|
void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
|
|
|
|
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) {
|
|
HCheckInstanceType* b = HCheckInstanceType::cast(other);
|
|
return check_ == b->check_;
|
|
}
|
|
|
|
private:
|
|
enum Check {
|
|
IS_SPEC_OBJECT,
|
|
IS_JS_ARRAY,
|
|
IS_STRING,
|
|
IS_SYMBOL,
|
|
LAST_INTERVAL_CHECK = IS_JS_ARRAY
|
|
};
|
|
|
|
const char* GetCheckName();
|
|
|
|
HCheckInstanceType(HValue* value, Check check)
|
|
: HUnaryOperation(value), check_(check) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
const Check check_;
|
|
};
|
|
|
|
|
|
class HCheckNonSmi: public HUnaryOperation {
|
|
public:
|
|
explicit HCheckNonSmi(HValue* value) : HUnaryOperation(value) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual HType CalculateInferredType();
|
|
|
|
#ifdef DEBUG
|
|
virtual void Verify();
|
|
#endif
|
|
|
|
virtual HValue* Canonicalize() {
|
|
HType value_type = value()->type();
|
|
if (!value_type.IsUninitialized() &&
|
|
(value_type.IsHeapNumber() ||
|
|
value_type.IsString() ||
|
|
value_type.IsBoolean() ||
|
|
value_type.IsNonPrimitive())) {
|
|
return NULL;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HCheckPrototypeMaps: public HTemplateInstruction<0> {
|
|
public:
|
|
HCheckPrototypeMaps(Handle<JSObject> prototype, Handle<JSObject> holder)
|
|
: prototype_(prototype), holder_(holder) {
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnMaps);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
virtual void Verify();
|
|
#endif
|
|
|
|
Handle<JSObject> prototype() const { return prototype_; }
|
|
Handle<JSObject> holder() const { return holder_; }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps)
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
virtual intptr_t Hashcode() {
|
|
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) {
|
|
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 Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual HType CalculateInferredType();
|
|
|
|
#ifdef DEBUG
|
|
virtual void Verify();
|
|
#endif
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HPhi: public HValue {
|
|
public:
|
|
explicit HPhi(int merged_index)
|
|
: inputs_(2),
|
|
merged_index_(merged_index),
|
|
phi_id_(-1),
|
|
is_live_(false),
|
|
is_convertible_to_integer_(true) {
|
|
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();
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return representation();
|
|
}
|
|
virtual HType CalculateInferredType();
|
|
virtual int OperandCount() { return inputs_.length(); }
|
|
virtual HValue* OperandAt(int index) { return inputs_[index]; }
|
|
HValue* GetRedundantReplacement();
|
|
void AddInput(HValue* value);
|
|
bool HasRealUses();
|
|
|
|
bool IsReceiver() { return merged_index_ == 0; }
|
|
|
|
int merged_index() const { return merged_index_; }
|
|
|
|
virtual void PrintTo(StringStream* stream);
|
|
|
|
#ifdef DEBUG
|
|
virtual void Verify();
|
|
#endif
|
|
|
|
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_; }
|
|
bool is_live() { return is_live_; }
|
|
void set_is_live(bool b) { is_live_ = b; }
|
|
|
|
static HPhi* cast(HValue* value) {
|
|
ASSERT(value->IsPhi());
|
|
return reinterpret_cast<HPhi*>(value);
|
|
}
|
|
virtual Opcode opcode() const { return HValue::kPhi; }
|
|
|
|
virtual bool IsConvertibleToInteger() const {
|
|
return is_convertible_to_integer_;
|
|
}
|
|
|
|
void set_is_convertible_to_integer(bool b) {
|
|
is_convertible_to_integer_ = b;
|
|
}
|
|
|
|
bool AllOperandsConvertibleToInteger() {
|
|
for (int i = 0; i < OperandCount(); ++i) {
|
|
if (!OperandAt(i)->IsConvertibleToInteger()) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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_;
|
|
bool is_live_;
|
|
bool is_convertible_to_integer_;
|
|
};
|
|
|
|
|
|
class HArgumentsObject: public HTemplateInstruction<0> {
|
|
public:
|
|
HArgumentsObject() {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kIsArguments);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
|
|
};
|
|
|
|
|
|
class HConstant: public HTemplateInstruction<0> {
|
|
public:
|
|
HConstant(Handle<Object> handle, Representation r);
|
|
|
|
Handle<Object> handle() const { return handle_; }
|
|
|
|
bool InOldSpace() const { return !HEAP->InNewSpace(*handle_); }
|
|
|
|
bool ImmortalImmovable() const {
|
|
Heap* heap = HEAP;
|
|
if (*handle_ == heap->undefined_value()) return true;
|
|
if (*handle_ == heap->null_value()) return true;
|
|
if (*handle_ == heap->true_value()) return true;
|
|
if (*handle_ == heap->false_value()) return true;
|
|
if (*handle_ == heap->the_hole_value()) return true;
|
|
if (*handle_ == heap->minus_zero_value()) return true;
|
|
if (*handle_ == heap->nan_value()) return true;
|
|
if (*handle_ == heap->empty_string()) return true;
|
|
return false;
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
virtual bool IsConvertibleToInteger() const {
|
|
if (handle_->IsSmi()) return true;
|
|
if (handle_->IsHeapNumber() &&
|
|
(HeapNumber::cast(*handle_)->value() ==
|
|
static_cast<double>(NumberToInt32(*handle_)))) return true;
|
|
return false;
|
|
}
|
|
|
|
virtual bool EmitAtUses() { return !representation().IsDouble(); }
|
|
virtual HValue* Canonicalize();
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
virtual HType CalculateInferredType();
|
|
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 HasNumberValue() const { return has_int32_value_ || has_double_value_; }
|
|
int32_t NumberValueAsInteger32() const {
|
|
ASSERT(HasNumberValue());
|
|
if (has_int32_value_) return int32_value_;
|
|
return DoubleToInt32(double_value_);
|
|
}
|
|
bool HasStringValue() const { return handle_->IsString(); }
|
|
|
|
bool ToBoolean() const;
|
|
|
|
virtual intptr_t Hashcode() {
|
|
ASSERT(!HEAP->allow_allocation(false));
|
|
intptr_t hash = reinterpret_cast<intptr_t>(*handle());
|
|
// Prevent smis from having fewer hash values when truncated to
|
|
// the least significant bits.
|
|
const int kShiftSize = kSmiShiftSize + kSmiTagSize;
|
|
STATIC_ASSERT(kShiftSize != 0);
|
|
return hash ^ (hash >> kShiftSize);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
virtual void Verify() { }
|
|
#endif
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Constant)
|
|
|
|
protected:
|
|
virtual Range* InferRange(Zone* zone);
|
|
|
|
virtual bool DataEquals(HValue* other) {
|
|
HConstant* other_constant = HConstant::cast(other);
|
|
return handle().is_identical_to(other_constant->handle());
|
|
}
|
|
|
|
private:
|
|
Handle<Object> handle_;
|
|
|
|
// 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_ : 1;
|
|
bool has_double_value_ : 1;
|
|
int32_t int32_value_;
|
|
double double_value_;
|
|
};
|
|
|
|
|
|
class HBinaryOperation: public HTemplateInstruction<3> {
|
|
public:
|
|
HBinaryOperation(HValue* context, HValue* left, HValue* right) {
|
|
ASSERT(left != NULL && right != NULL);
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, left);
|
|
SetOperandAt(2, right);
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* left() { return OperandAt(1); }
|
|
HValue* right() { return OperandAt(2); }
|
|
|
|
// TODO(kasperl): Move these helpers to the IA-32 Lithium
|
|
// instruction sequence builder.
|
|
HValue* LeastConstantOperand() {
|
|
if (IsCommutative() && left()->IsConstant()) return right();
|
|
return left();
|
|
}
|
|
HValue* MostConstantOperand() {
|
|
if (IsCommutative() && left()->IsConstant()) return left();
|
|
return right();
|
|
}
|
|
|
|
virtual bool IsCommutative() const { return false; }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
};
|
|
|
|
|
|
class HWrapReceiver: public HTemplateInstruction<2> {
|
|
public:
|
|
HWrapReceiver(HValue* receiver, HValue* function) {
|
|
set_representation(Representation::Tagged());
|
|
SetOperandAt(0, receiver);
|
|
SetOperandAt(1, function);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* receiver() { return OperandAt(0); }
|
|
HValue* function() { return OperandAt(1); }
|
|
|
|
virtual HValue* Canonicalize();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
|
|
};
|
|
|
|
|
|
class HApplyArguments: public HTemplateInstruction<4> {
|
|
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);
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
// The length is untagged, all other inputs are tagged.
|
|
return (index == 2)
|
|
? Representation::Integer32()
|
|
: Representation::Tagged();
|
|
}
|
|
|
|
HValue* function() { return OperandAt(0); }
|
|
HValue* receiver() { return OperandAt(1); }
|
|
HValue* length() { return OperandAt(2); }
|
|
HValue* elements() { return OperandAt(3); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
|
|
};
|
|
|
|
|
|
class HArgumentsElements: public HTemplateInstruction<0> {
|
|
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)
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HArgumentsLength: public HUnaryOperation {
|
|
public:
|
|
explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
|
|
set_representation(Representation::Integer32());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HAccessArgumentsAt: public HTemplateInstruction<3> {
|
|
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);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
// The arguments elements is considered tagged.
|
|
return index == 0
|
|
? Representation::Tagged()
|
|
: Representation::Integer32();
|
|
}
|
|
|
|
HValue* arguments() { return OperandAt(0); }
|
|
HValue* length() { return OperandAt(1); }
|
|
HValue* index() { return OperandAt(2); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
|
|
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HBoundsCheck: public HTemplateInstruction<2> {
|
|
public:
|
|
HBoundsCheck(HValue* index, HValue* length) {
|
|
SetOperandAt(0, index);
|
|
SetOperandAt(1, length);
|
|
set_representation(Representation::Integer32());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Integer32();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
HValue* index() { return OperandAt(0); }
|
|
HValue* length() { return OperandAt(1); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HBitwiseBinaryOperation: public HBinaryOperation {
|
|
public:
|
|
HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right)
|
|
: HBinaryOperation(context, left, right) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kFlexibleRepresentation);
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return index == 0
|
|
? Representation::Tagged()
|
|
: representation();
|
|
}
|
|
|
|
virtual void RepresentationChanged(Representation to) {
|
|
if (!to.IsTagged()) {
|
|
ASSERT(to.IsInteger32());
|
|
ClearAllSideEffects();
|
|
SetFlag(kTruncatingToInt32);
|
|
SetFlag(kUseGVN);
|
|
}
|
|
}
|
|
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
|
|
};
|
|
|
|
|
|
class HArithmeticBinaryOperation: public HBinaryOperation {
|
|
public:
|
|
HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
|
|
: HBinaryOperation(context, left, right) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kFlexibleRepresentation);
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
virtual void RepresentationChanged(Representation to) {
|
|
if (!to.IsTagged()) {
|
|
ClearAllSideEffects();
|
|
SetFlag(kUseGVN);
|
|
}
|
|
}
|
|
|
|
virtual HType CalculateInferredType();
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return index == 0
|
|
? Representation::Tagged()
|
|
: representation();
|
|
}
|
|
|
|
virtual Representation InferredRepresentation() {
|
|
if (left()->representation().Equals(right()->representation())) {
|
|
return left()->representation();
|
|
}
|
|
return HValue::InferredRepresentation();
|
|
}
|
|
};
|
|
|
|
|
|
class HCompareGeneric: public HBinaryOperation {
|
|
public:
|
|
HCompareGeneric(HValue* context,
|
|
HValue* left,
|
|
HValue* right,
|
|
Token::Value token)
|
|
: HBinaryOperation(context, left, right), token_(token) {
|
|
ASSERT(Token::IsCompareOp(token));
|
|
set_representation(Representation::Tagged());
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
Representation GetInputRepresentation() const {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
Token::Value token() const { return token_; }
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
|
|
|
|
private:
|
|
Token::Value token_;
|
|
};
|
|
|
|
|
|
class HCompareIDAndBranch: public HTemplateControlInstruction<2, 2> {
|
|
public:
|
|
HCompareIDAndBranch(HValue* left, HValue* right, Token::Value token)
|
|
: token_(token) {
|
|
ASSERT(Token::IsCompareOp(token));
|
|
SetOperandAt(0, left);
|
|
SetOperandAt(1, right);
|
|
}
|
|
|
|
HValue* left() { return OperandAt(0); }
|
|
HValue* right() { return OperandAt(1); }
|
|
Token::Value token() const { return token_; }
|
|
|
|
void SetInputRepresentation(Representation r);
|
|
Representation GetInputRepresentation() const {
|
|
return input_representation_;
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return input_representation_;
|
|
}
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CompareIDAndBranch)
|
|
|
|
private:
|
|
Representation input_representation_;
|
|
Token::Value token_;
|
|
};
|
|
|
|
|
|
class HCompareObjectEqAndBranch: public HTemplateControlInstruction<2, 2> {
|
|
public:
|
|
HCompareObjectEqAndBranch(HValue* left, HValue* right) {
|
|
SetOperandAt(0, left);
|
|
SetOperandAt(1, right);
|
|
}
|
|
|
|
HValue* left() { return OperandAt(0); }
|
|
HValue* right() { return OperandAt(1); }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
|
|
};
|
|
|
|
|
|
class HCompareConstantEqAndBranch: public HUnaryControlInstruction {
|
|
public:
|
|
HCompareConstantEqAndBranch(HValue* left, int right, Token::Value op)
|
|
: HUnaryControlInstruction(left, NULL, NULL), op_(op), right_(right) {
|
|
ASSERT(op == Token::EQ_STRICT);
|
|
}
|
|
|
|
Token::Value op() const { return op_; }
|
|
HValue* left() { return value(); }
|
|
int right() const { return right_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Integer32();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CompareConstantEqAndBranch);
|
|
|
|
private:
|
|
const Token::Value op_;
|
|
const int right_;
|
|
};
|
|
|
|
|
|
class HIsNilAndBranch: public HUnaryControlInstruction {
|
|
public:
|
|
HIsNilAndBranch(HValue* value, EqualityKind kind, NilValue nil)
|
|
: HUnaryControlInstruction(value, NULL, NULL), kind_(kind), nil_(nil) { }
|
|
|
|
EqualityKind kind() const { return kind_; }
|
|
NilValue nil() const { return nil_; }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch)
|
|
|
|
private:
|
|
EqualityKind kind_;
|
|
NilValue nil_;
|
|
};
|
|
|
|
|
|
class HIsObjectAndBranch: public HUnaryControlInstruction {
|
|
public:
|
|
explicit HIsObjectAndBranch(HValue* value)
|
|
: HUnaryControlInstruction(value, NULL, NULL) { }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
|
|
};
|
|
|
|
class HIsStringAndBranch: public HUnaryControlInstruction {
|
|
public:
|
|
explicit HIsStringAndBranch(HValue* value)
|
|
: HUnaryControlInstruction(value, NULL, NULL) { }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
|
|
};
|
|
|
|
|
|
class HIsSmiAndBranch: public HUnaryControlInstruction {
|
|
public:
|
|
explicit HIsSmiAndBranch(HValue* value)
|
|
: HUnaryControlInstruction(value, NULL, NULL) { }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HIsUndetectableAndBranch: public HUnaryControlInstruction {
|
|
public:
|
|
explicit HIsUndetectableAndBranch(HValue* value)
|
|
: HUnaryControlInstruction(value, NULL, NULL) { }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
|
|
};
|
|
|
|
|
|
class HStringCompareAndBranch: public HTemplateControlInstruction<2, 3> {
|
|
public:
|
|
HStringCompareAndBranch(HValue* context,
|
|
HValue* left,
|
|
HValue* right,
|
|
Token::Value token)
|
|
: token_(token) {
|
|
ASSERT(Token::IsCompareOp(token));
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, left);
|
|
SetOperandAt(2, right);
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* left() { return OperandAt(1); }
|
|
HValue* right() { return OperandAt(2); }
|
|
Token::Value token() const { return token_; }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
Representation GetInputRepresentation() const {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
|
|
|
|
private:
|
|
Token::Value token_;
|
|
};
|
|
|
|
|
|
class HIsConstructCallAndBranch: public HTemplateControlInstruction<2, 0> {
|
|
public:
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch)
|
|
};
|
|
|
|
|
|
class HHasInstanceTypeAndBranch: public HUnaryControlInstruction {
|
|
public:
|
|
HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
|
|
: HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
|
|
HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
|
|
: HUnaryControlInstruction(value, NULL, NULL), 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);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
|
|
|
|
private:
|
|
InstanceType from_;
|
|
InstanceType to_; // Inclusive range, not all combinations work.
|
|
};
|
|
|
|
|
|
class HHasCachedArrayIndexAndBranch: public HUnaryControlInstruction {
|
|
public:
|
|
explicit HHasCachedArrayIndexAndBranch(HValue* value)
|
|
: HUnaryControlInstruction(value, NULL, NULL) { }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
|
|
};
|
|
|
|
|
|
class HGetCachedArrayIndex: public HUnaryOperation {
|
|
public:
|
|
explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HClassOfTestAndBranch: public HUnaryControlInstruction {
|
|
public:
|
|
HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
|
|
: HUnaryControlInstruction(value, NULL, NULL),
|
|
class_name_(class_name) { }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
Handle<String> class_name() const { return class_name_; }
|
|
|
|
private:
|
|
Handle<String> class_name_;
|
|
};
|
|
|
|
|
|
class HTypeofIsAndBranch: public HUnaryControlInstruction {
|
|
public:
|
|
HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
|
|
: HUnaryControlInstruction(value, NULL, NULL),
|
|
type_literal_(type_literal) { }
|
|
|
|
Handle<String> type_literal() { return type_literal_; }
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
private:
|
|
Handle<String> type_literal_;
|
|
};
|
|
|
|
|
|
class HInstanceOf: public HBinaryOperation {
|
|
public:
|
|
HInstanceOf(HValue* context, HValue* left, HValue* right)
|
|
: HBinaryOperation(context, left, right) {
|
|
set_representation(Representation::Tagged());
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual HType CalculateInferredType();
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
|
|
};
|
|
|
|
|
|
class HInstanceOfKnownGlobal: public HTemplateInstruction<2> {
|
|
public:
|
|
HInstanceOfKnownGlobal(HValue* context,
|
|
HValue* left,
|
|
Handle<JSFunction> right)
|
|
: function_(right) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, left);
|
|
set_representation(Representation::Tagged());
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* left() { return OperandAt(1); }
|
|
Handle<JSFunction> function() { return function_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal)
|
|
|
|
private:
|
|
Handle<JSFunction> function_;
|
|
};
|
|
|
|
|
|
class HPower: public HTemplateInstruction<2> {
|
|
public:
|
|
HPower(HValue* left, HValue* right) {
|
|
SetOperandAt(0, left);
|
|
SetOperandAt(1, right);
|
|
set_representation(Representation::Double());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
HValue* left() { return OperandAt(0); }
|
|
HValue* right() { return OperandAt(1); }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return index == 0
|
|
? Representation::Double()
|
|
: Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Power)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HRandom: public HTemplateInstruction<1> {
|
|
public:
|
|
explicit HRandom(HValue* global_object) {
|
|
SetOperandAt(0, global_object);
|
|
set_representation(Representation::Double());
|
|
}
|
|
|
|
HValue* global_object() { return OperandAt(0); }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Random)
|
|
};
|
|
|
|
|
|
class HAdd: public HArithmeticBinaryOperation {
|
|
public:
|
|
HAdd(HValue* context, HValue* left, HValue* right)
|
|
: HArithmeticBinaryOperation(context, 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);
|
|
|
|
static HInstruction* NewHAdd(Zone* zone,
|
|
HValue* context,
|
|
HValue* left,
|
|
HValue* right);
|
|
|
|
virtual HType CalculateInferredType();
|
|
|
|
virtual HValue* Canonicalize();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Add)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
};
|
|
|
|
|
|
class HSub: public HArithmeticBinaryOperation {
|
|
public:
|
|
HSub(HValue* context, HValue* left, HValue* right)
|
|
: HArithmeticBinaryOperation(context, left, right) {
|
|
SetFlag(kCanOverflow);
|
|
}
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
virtual HValue* Canonicalize();
|
|
|
|
static HInstruction* NewHSub(Zone* zone,
|
|
HValue* context,
|
|
HValue* left,
|
|
HValue* right);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Sub)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
};
|
|
|
|
|
|
class HMul: public HArithmeticBinaryOperation {
|
|
public:
|
|
HMul(HValue* context, HValue* left, HValue* right)
|
|
: HArithmeticBinaryOperation(context, 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();
|
|
}
|
|
|
|
static HInstruction* NewHMul(Zone* zone,
|
|
HValue* context,
|
|
HValue* left,
|
|
HValue* right);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Mul)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
};
|
|
|
|
|
|
class HMod: public HArithmeticBinaryOperation {
|
|
public:
|
|
HMod(HValue* context, HValue* left, HValue* right)
|
|
: HArithmeticBinaryOperation(context, left, right) {
|
|
SetFlag(kCanBeDivByZero);
|
|
}
|
|
|
|
bool HasPowerOf2Divisor() {
|
|
if (right()->IsConstant() &&
|
|
HConstant::cast(right())->HasInteger32Value()) {
|
|
int32_t value = HConstant::cast(right())->Integer32Value();
|
|
return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
static HInstruction* NewHMod(Zone* zone,
|
|
HValue* context,
|
|
HValue* left,
|
|
HValue* right);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Mod)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
};
|
|
|
|
|
|
class HDiv: public HArithmeticBinaryOperation {
|
|
public:
|
|
HDiv(HValue* context, HValue* left, HValue* right)
|
|
: HArithmeticBinaryOperation(context, left, right) {
|
|
SetFlag(kCanBeDivByZero);
|
|
SetFlag(kCanOverflow);
|
|
}
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
static HInstruction* NewHDiv(Zone* zone,
|
|
HValue* context,
|
|
HValue* left,
|
|
HValue* right);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Div)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
};
|
|
|
|
|
|
class HBitwise: public HBitwiseBinaryOperation {
|
|
public:
|
|
HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right)
|
|
: HBitwiseBinaryOperation(context, left, right), op_(op) {
|
|
ASSERT(op == Token::BIT_AND ||
|
|
op == Token::BIT_OR ||
|
|
op == Token::BIT_XOR);
|
|
}
|
|
|
|
Token::Value op() const { return op_; }
|
|
|
|
virtual bool IsCommutative() const { return true; }
|
|
|
|
virtual HValue* Canonicalize();
|
|
|
|
static HInstruction* NewHBitwise(Zone* zone,
|
|
Token::Value op,
|
|
HValue* context,
|
|
HValue* left,
|
|
HValue* right);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Bitwise)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
return op() == HBitwise::cast(other)->op();
|
|
}
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
|
|
private:
|
|
Token::Value op_;
|
|
};
|
|
|
|
|
|
class HShl: public HBitwiseBinaryOperation {
|
|
public:
|
|
HShl(HValue* context, HValue* left, HValue* right)
|
|
: HBitwiseBinaryOperation(context, left, right) { }
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
|
|
static HInstruction* NewHShl(Zone* zone,
|
|
HValue* context,
|
|
HValue* left,
|
|
HValue* right);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Shl)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HShr: public HBitwiseBinaryOperation {
|
|
public:
|
|
HShr(HValue* context, HValue* left, HValue* right)
|
|
: HBitwiseBinaryOperation(context, left, right) { }
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
|
|
static HInstruction* NewHShr(Zone* zone,
|
|
HValue* context,
|
|
HValue* left,
|
|
HValue* right);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Shr)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HSar: public HBitwiseBinaryOperation {
|
|
public:
|
|
HSar(HValue* context, HValue* left, HValue* right)
|
|
: HBitwiseBinaryOperation(context, left, right) { }
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
|
|
static HInstruction* NewHSar(Zone* zone,
|
|
HValue* context,
|
|
HValue* left,
|
|
HValue* right);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Sar)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HOsrEntry: public HTemplateInstruction<0> {
|
|
public:
|
|
explicit HOsrEntry(int ast_id) : ast_id_(ast_id) {
|
|
SetGVNFlag(kChangesOsrEntries);
|
|
}
|
|
|
|
int ast_id() const { return ast_id_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
|
|
|
|
private:
|
|
int ast_id_;
|
|
};
|
|
|
|
|
|
class HParameter: public HTemplateInstruction<0> {
|
|
public:
|
|
explicit HParameter(unsigned index) : index_(index) {
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
unsigned index() const { return index_; }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Parameter)
|
|
|
|
private:
|
|
unsigned index_;
|
|
};
|
|
|
|
|
|
class HCallStub: public HUnaryCall {
|
|
public:
|
|
HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
|
|
: HUnaryCall(context, argument_count),
|
|
major_key_(major_key),
|
|
transcendental_type_(TranscendentalCache::kNumberOfCaches) {
|
|
}
|
|
|
|
CodeStub::Major major_key() { return major_key_; }
|
|
|
|
HValue* context() { return value(); }
|
|
|
|
void set_transcendental_type(TranscendentalCache::Type transcendental_type) {
|
|
transcendental_type_ = transcendental_type;
|
|
}
|
|
TranscendentalCache::Type transcendental_type() {
|
|
return transcendental_type_;
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallStub)
|
|
|
|
private:
|
|
CodeStub::Major major_key_;
|
|
TranscendentalCache::Type transcendental_type_;
|
|
};
|
|
|
|
|
|
class HUnknownOSRValue: public HTemplateInstruction<0> {
|
|
public:
|
|
HUnknownOSRValue()
|
|
: incoming_value_(NULL) {
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
void set_incoming_value(HPhi* value) {
|
|
incoming_value_ = value;
|
|
}
|
|
|
|
HPhi* incoming_value() {
|
|
return incoming_value_;
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
|
|
|
|
private:
|
|
HPhi* incoming_value_;
|
|
};
|
|
|
|
|
|
class HLoadGlobalCell: public HTemplateInstruction<0> {
|
|
public:
|
|
HLoadGlobalCell(Handle<JSGlobalPropertyCell> cell, PropertyDetails details)
|
|
: cell_(cell), details_(details) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnGlobalVars);
|
|
}
|
|
|
|
Handle<JSGlobalPropertyCell> cell() const { return cell_; }
|
|
bool RequiresHoleCheck();
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual intptr_t Hashcode() {
|
|
ASSERT(!HEAP->allow_allocation(false));
|
|
return reinterpret_cast<intptr_t>(*cell_);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::None();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
HLoadGlobalCell* b = HLoadGlobalCell::cast(other);
|
|
return cell_.is_identical_to(b->cell());
|
|
}
|
|
|
|
private:
|
|
Handle<JSGlobalPropertyCell> cell_;
|
|
PropertyDetails details_;
|
|
};
|
|
|
|
|
|
class HLoadGlobalGeneric: public HTemplateInstruction<2> {
|
|
public:
|
|
HLoadGlobalGeneric(HValue* context,
|
|
HValue* global_object,
|
|
Handle<Object> name,
|
|
bool for_typeof)
|
|
: name_(name),
|
|
for_typeof_(for_typeof) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, global_object);
|
|
set_representation(Representation::Tagged());
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* global_object() { return OperandAt(1); }
|
|
Handle<Object> name() const { return name_; }
|
|
bool for_typeof() const { return for_typeof_; }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
|
|
|
|
private:
|
|
Handle<Object> name_;
|
|
bool for_typeof_;
|
|
};
|
|
|
|
|
|
inline bool StoringValueNeedsWriteBarrier(HValue* value) {
|
|
return !value->type().IsBoolean()
|
|
&& !value->type().IsSmi()
|
|
&& !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
|
|
}
|
|
|
|
|
|
class HStoreGlobalCell: public HUnaryOperation {
|
|
public:
|
|
HStoreGlobalCell(HValue* value,
|
|
Handle<JSGlobalPropertyCell> cell,
|
|
PropertyDetails details)
|
|
: HUnaryOperation(value),
|
|
cell_(cell),
|
|
details_(details) {
|
|
SetGVNFlag(kChangesGlobalVars);
|
|
}
|
|
|
|
Handle<JSGlobalPropertyCell> cell() const { return cell_; }
|
|
bool RequiresHoleCheck() {
|
|
return !details_.IsDontDelete() || details_.IsReadOnly();
|
|
}
|
|
bool NeedsWriteBarrier() {
|
|
return StoringValueNeedsWriteBarrier(value());
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell)
|
|
|
|
private:
|
|
Handle<JSGlobalPropertyCell> cell_;
|
|
PropertyDetails details_;
|
|
};
|
|
|
|
|
|
class HStoreGlobalGeneric: public HTemplateInstruction<3> {
|
|
public:
|
|
HStoreGlobalGeneric(HValue* context,
|
|
HValue* global_object,
|
|
Handle<Object> name,
|
|
HValue* value,
|
|
StrictModeFlag strict_mode_flag)
|
|
: name_(name),
|
|
strict_mode_flag_(strict_mode_flag) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, global_object);
|
|
SetOperandAt(2, value);
|
|
set_representation(Representation::Tagged());
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* global_object() { return OperandAt(1); }
|
|
Handle<Object> name() const { return name_; }
|
|
HValue* value() { return OperandAt(2); }
|
|
StrictModeFlag strict_mode_flag() { return strict_mode_flag_; }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric)
|
|
|
|
private:
|
|
Handle<Object> name_;
|
|
StrictModeFlag strict_mode_flag_;
|
|
};
|
|
|
|
|
|
class HLoadContextSlot: public HUnaryOperation {
|
|
public:
|
|
enum Mode {
|
|
// Perform a normal load of the context slot without checking its value.
|
|
kNoCheck,
|
|
// Load and check the value of the context slot. Deoptimize if it's the
|
|
// hole value. This is used for checking for loading of uninitialized
|
|
// harmony bindings where we deoptimize into full-codegen generated code
|
|
// which will subsequently throw a reference error.
|
|
kCheckDeoptimize,
|
|
// Load and check the value of the context slot. Return undefined if it's
|
|
// the hole value. This is used for non-harmony const assignments
|
|
kCheckReturnUndefined
|
|
};
|
|
|
|
HLoadContextSlot(HValue* context, Variable* var)
|
|
: HUnaryOperation(context), slot_index_(var->index()) {
|
|
ASSERT(var->IsContextSlot());
|
|
switch (var->mode()) {
|
|
case LET:
|
|
case CONST_HARMONY:
|
|
mode_ = kCheckDeoptimize;
|
|
break;
|
|
case CONST:
|
|
mode_ = kCheckReturnUndefined;
|
|
break;
|
|
default:
|
|
mode_ = kNoCheck;
|
|
}
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnContextSlots);
|
|
}
|
|
|
|
int slot_index() const { return slot_index_; }
|
|
Mode mode() const { return mode_; }
|
|
|
|
bool DeoptimizesOnHole() {
|
|
return mode_ == kCheckDeoptimize;
|
|
}
|
|
|
|
bool RequiresHoleCheck() {
|
|
return mode_ != kNoCheck;
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
HLoadContextSlot* b = HLoadContextSlot::cast(other);
|
|
return (slot_index() == b->slot_index());
|
|
}
|
|
|
|
private:
|
|
int slot_index_;
|
|
Mode mode_;
|
|
};
|
|
|
|
|
|
class HStoreContextSlot: public HTemplateInstruction<2> {
|
|
public:
|
|
enum Mode {
|
|
// Perform a normal store to the context slot without checking its previous
|
|
// value.
|
|
kNoCheck,
|
|
// Check the previous value of the context slot and deoptimize if it's the
|
|
// hole value. This is used for checking for assignments to uninitialized
|
|
// harmony bindings where we deoptimize into full-codegen generated code
|
|
// which will subsequently throw a reference error.
|
|
kCheckDeoptimize,
|
|
// Check the previous value and ignore assignment if it isn't a hole value
|
|
kCheckIgnoreAssignment
|
|
};
|
|
|
|
HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
|
|
: slot_index_(slot_index), mode_(mode) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, value);
|
|
SetGVNFlag(kChangesContextSlots);
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* value() { return OperandAt(1); }
|
|
int slot_index() const { return slot_index_; }
|
|
Mode mode() const { return mode_; }
|
|
|
|
bool NeedsWriteBarrier() {
|
|
return StoringValueNeedsWriteBarrier(value());
|
|
}
|
|
|
|
bool DeoptimizesOnHole() {
|
|
return mode_ == kCheckDeoptimize;
|
|
}
|
|
|
|
bool RequiresHoleCheck() {
|
|
return mode_ != kNoCheck;
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
|
|
|
|
private:
|
|
int slot_index_;
|
|
Mode mode_;
|
|
};
|
|
|
|
|
|
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);
|
|
SetGVNFlag(kDependsOnMaps);
|
|
if (is_in_object) {
|
|
SetGVNFlag(kDependsOnInobjectFields);
|
|
} else {
|
|
SetGVNFlag(kDependsOnBackingStoreFields);
|
|
}
|
|
}
|
|
|
|
HValue* object() { return OperandAt(0); }
|
|
bool is_in_object() const { return is_in_object_; }
|
|
int offset() const { return offset_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
HLoadNamedField* b = HLoadNamedField::cast(other);
|
|
return is_in_object_ == b->is_in_object_ && offset_ == b->offset_;
|
|
}
|
|
|
|
private:
|
|
bool is_in_object_;
|
|
int offset_;
|
|
};
|
|
|
|
|
|
class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> {
|
|
public:
|
|
HLoadNamedFieldPolymorphic(HValue* context,
|
|
HValue* object,
|
|
SmallMapList* types,
|
|
Handle<String> name);
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* object() { return OperandAt(1); }
|
|
SmallMapList* types() { return &types_; }
|
|
Handle<String> name() { return name_; }
|
|
bool need_generic() { return need_generic_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadNamedFieldPolymorphic)
|
|
|
|
static const int kMaxLoadPolymorphism = 4;
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* value);
|
|
|
|
private:
|
|
SmallMapList types_;
|
|
Handle<String> name_;
|
|
bool need_generic_;
|
|
};
|
|
|
|
|
|
|
|
class HLoadNamedGeneric: public HTemplateInstruction<2> {
|
|
public:
|
|
HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
|
|
: name_(name) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, object);
|
|
set_representation(Representation::Tagged());
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* object() { return OperandAt(1); }
|
|
Handle<Object> name() const { return name_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
|
|
|
|
private:
|
|
Handle<Object> name_;
|
|
};
|
|
|
|
|
|
class HLoadFunctionPrototype: public HUnaryOperation {
|
|
public:
|
|
explicit HLoadFunctionPrototype(HValue* function)
|
|
: HUnaryOperation(function) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnCalls);
|
|
}
|
|
|
|
HValue* function() { return OperandAt(0); }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HLoadKeyedFastElement: public HTemplateInstruction<2> {
|
|
public:
|
|
enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK };
|
|
|
|
HLoadKeyedFastElement(HValue* obj,
|
|
HValue* key,
|
|
HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
|
|
: hole_check_mode_(hole_check_mode) {
|
|
SetOperandAt(0, obj);
|
|
SetOperandAt(1, key);
|
|
set_representation(Representation::Tagged());
|
|
SetGVNFlag(kDependsOnArrayElements);
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
HValue* object() { return OperandAt(0); }
|
|
HValue* key() { return OperandAt(1); }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
// The key is supposed to be Integer32.
|
|
return index == 0
|
|
? Representation::Tagged()
|
|
: Representation::Integer32();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
bool RequiresHoleCheck();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
if (!other->IsLoadKeyedFastElement()) return false;
|
|
HLoadKeyedFastElement* other_load = HLoadKeyedFastElement::cast(other);
|
|
return hole_check_mode_ == other_load->hole_check_mode_;
|
|
}
|
|
|
|
private:
|
|
HoleCheckMode hole_check_mode_;
|
|
};
|
|
|
|
|
|
class HLoadKeyedFastDoubleElement: public HTemplateInstruction<2> {
|
|
public:
|
|
HLoadKeyedFastDoubleElement(HValue* elements, HValue* key) {
|
|
SetOperandAt(0, elements);
|
|
SetOperandAt(1, key);
|
|
set_representation(Representation::Double());
|
|
SetGVNFlag(kDependsOnDoubleArrayElements);
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
HValue* elements() { return OperandAt(0); }
|
|
HValue* key() { return OperandAt(1); }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
// The key is supposed to be Integer32.
|
|
return index == 0
|
|
? Representation::Tagged()
|
|
: Representation::Integer32();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
|
|
public:
|
|
HLoadKeyedSpecializedArrayElement(HValue* external_elements,
|
|
HValue* key,
|
|
ElementsKind elements_kind)
|
|
: elements_kind_(elements_kind) {
|
|
SetOperandAt(0, external_elements);
|
|
SetOperandAt(1, key);
|
|
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
|
|
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
|
|
set_representation(Representation::Double());
|
|
} else {
|
|
set_representation(Representation::Integer32());
|
|
}
|
|
SetGVNFlag(kDependsOnSpecializedArrayElements);
|
|
// Native code could change the specialized array.
|
|
SetGVNFlag(kDependsOnCalls);
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
// The key is supposed to be Integer32, but the base pointer
|
|
// for the element load is a naked pointer.
|
|
return index == 0
|
|
? Representation::External()
|
|
: Representation::Integer32();
|
|
}
|
|
|
|
HValue* external_pointer() { return OperandAt(0); }
|
|
HValue* key() { return OperandAt(1); }
|
|
ElementsKind elements_kind() const { return elements_kind_; }
|
|
|
|
virtual Range* InferRange(Zone* zone);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
if (!other->IsLoadKeyedSpecializedArrayElement()) return false;
|
|
HLoadKeyedSpecializedArrayElement* cast_other =
|
|
HLoadKeyedSpecializedArrayElement::cast(other);
|
|
return elements_kind_ == cast_other->elements_kind();
|
|
}
|
|
|
|
private:
|
|
ElementsKind elements_kind_;
|
|
};
|
|
|
|
|
|
class HLoadKeyedGeneric: public HTemplateInstruction<3> {
|
|
public:
|
|
HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key) {
|
|
set_representation(Representation::Tagged());
|
|
SetOperandAt(0, obj);
|
|
SetOperandAt(1, key);
|
|
SetOperandAt(2, context);
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
HValue* object() { return OperandAt(0); }
|
|
HValue* key() { return OperandAt(1); }
|
|
HValue* context() { return OperandAt(2); }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual HValue* Canonicalize();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric)
|
|
};
|
|
|
|
|
|
class HStoreNamedField: public HTemplateInstruction<2> {
|
|
public:
|
|
HStoreNamedField(HValue* obj,
|
|
Handle<String> name,
|
|
HValue* val,
|
|
bool in_object,
|
|
int offset)
|
|
: name_(name),
|
|
is_in_object_(in_object),
|
|
offset_(offset) {
|
|
SetOperandAt(0, obj);
|
|
SetOperandAt(1, val);
|
|
if (is_in_object_) {
|
|
SetGVNFlag(kChangesInobjectFields);
|
|
} else {
|
|
SetGVNFlag(kChangesBackingStoreFields);
|
|
}
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
HValue* object() { return OperandAt(0); }
|
|
HValue* value() { return OperandAt(1); }
|
|
|
|
Handle<String> name() const { return name_; }
|
|
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; }
|
|
|
|
bool NeedsWriteBarrier() {
|
|
return StoringValueNeedsWriteBarrier(value());
|
|
}
|
|
|
|
private:
|
|
Handle<String> name_;
|
|
bool is_in_object_;
|
|
int offset_;
|
|
Handle<Map> transition_;
|
|
};
|
|
|
|
|
|
class HStoreNamedGeneric: public HTemplateInstruction<3> {
|
|
public:
|
|
HStoreNamedGeneric(HValue* context,
|
|
HValue* object,
|
|
Handle<String> name,
|
|
HValue* value,
|
|
StrictModeFlag strict_mode_flag)
|
|
: name_(name),
|
|
strict_mode_flag_(strict_mode_flag) {
|
|
SetOperandAt(0, object);
|
|
SetOperandAt(1, value);
|
|
SetOperandAt(2, context);
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
HValue* object() { return OperandAt(0); }
|
|
HValue* value() { return OperandAt(1); }
|
|
HValue* context() { return OperandAt(2); }
|
|
Handle<String> name() { return name_; }
|
|
StrictModeFlag strict_mode_flag() { return strict_mode_flag_; }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric)
|
|
|
|
private:
|
|
Handle<String> name_;
|
|
StrictModeFlag strict_mode_flag_;
|
|
};
|
|
|
|
|
|
class HStoreKeyedFastElement: public HTemplateInstruction<3> {
|
|
public:
|
|
HStoreKeyedFastElement(HValue* obj, HValue* key, HValue* val,
|
|
ElementsKind elements_kind = FAST_ELEMENTS)
|
|
: elements_kind_(elements_kind) {
|
|
SetOperandAt(0, obj);
|
|
SetOperandAt(1, key);
|
|
SetOperandAt(2, val);
|
|
SetGVNFlag(kChangesArrayElements);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
// The key is supposed to be Integer32.
|
|
return index == 1
|
|
? Representation::Integer32()
|
|
: Representation::Tagged();
|
|
}
|
|
|
|
HValue* object() { return OperandAt(0); }
|
|
HValue* key() { return OperandAt(1); }
|
|
HValue* value() { return OperandAt(2); }
|
|
bool value_is_smi() {
|
|
return elements_kind_ == FAST_SMI_ONLY_ELEMENTS;
|
|
}
|
|
|
|
bool NeedsWriteBarrier() {
|
|
if (value_is_smi()) {
|
|
return false;
|
|
} else {
|
|
return StoringValueNeedsWriteBarrier(value());
|
|
}
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement)
|
|
|
|
private:
|
|
ElementsKind elements_kind_;
|
|
};
|
|
|
|
|
|
class HStoreKeyedFastDoubleElement: public HTemplateInstruction<3> {
|
|
public:
|
|
HStoreKeyedFastDoubleElement(HValue* elements,
|
|
HValue* key,
|
|
HValue* val) {
|
|
SetOperandAt(0, elements);
|
|
SetOperandAt(1, key);
|
|
SetOperandAt(2, val);
|
|
SetGVNFlag(kChangesDoubleArrayElements);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
if (index == 1) {
|
|
return Representation::Integer32();
|
|
} else if (index == 2) {
|
|
return Representation::Double();
|
|
} else {
|
|
return Representation::Tagged();
|
|
}
|
|
}
|
|
|
|
HValue* elements() { return OperandAt(0); }
|
|
HValue* key() { return OperandAt(1); }
|
|
HValue* value() { return OperandAt(2); }
|
|
|
|
bool NeedsWriteBarrier() {
|
|
return StoringValueNeedsWriteBarrier(value());
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement)
|
|
};
|
|
|
|
|
|
class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
|
|
public:
|
|
HStoreKeyedSpecializedArrayElement(HValue* external_elements,
|
|
HValue* key,
|
|
HValue* val,
|
|
ElementsKind elements_kind)
|
|
: elements_kind_(elements_kind) {
|
|
SetGVNFlag(kChangesSpecializedArrayElements);
|
|
SetOperandAt(0, external_elements);
|
|
SetOperandAt(1, key);
|
|
SetOperandAt(2, val);
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
if (index == 0) {
|
|
return Representation::External();
|
|
} else {
|
|
bool float_or_double_elements =
|
|
elements_kind() == EXTERNAL_FLOAT_ELEMENTS ||
|
|
elements_kind() == EXTERNAL_DOUBLE_ELEMENTS;
|
|
if (index == 2 && float_or_double_elements) {
|
|
return Representation::Double();
|
|
} else {
|
|
return Representation::Integer32();
|
|
}
|
|
}
|
|
}
|
|
|
|
HValue* external_pointer() { return OperandAt(0); }
|
|
HValue* key() { return OperandAt(1); }
|
|
HValue* value() { return OperandAt(2); }
|
|
ElementsKind elements_kind() const { return elements_kind_; }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement)
|
|
|
|
private:
|
|
ElementsKind elements_kind_;
|
|
};
|
|
|
|
|
|
class HStoreKeyedGeneric: public HTemplateInstruction<4> {
|
|
public:
|
|
HStoreKeyedGeneric(HValue* context,
|
|
HValue* object,
|
|
HValue* key,
|
|
HValue* value,
|
|
StrictModeFlag strict_mode_flag)
|
|
: strict_mode_flag_(strict_mode_flag) {
|
|
SetOperandAt(0, object);
|
|
SetOperandAt(1, key);
|
|
SetOperandAt(2, value);
|
|
SetOperandAt(3, context);
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
HValue* object() { return OperandAt(0); }
|
|
HValue* key() { return OperandAt(1); }
|
|
HValue* value() { return OperandAt(2); }
|
|
HValue* context() { return OperandAt(3); }
|
|
StrictModeFlag strict_mode_flag() { return strict_mode_flag_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric)
|
|
|
|
private:
|
|
StrictModeFlag strict_mode_flag_;
|
|
};
|
|
|
|
|
|
class HTransitionElementsKind: public HTemplateInstruction<1> {
|
|
public:
|
|
HTransitionElementsKind(HValue* object,
|
|
Handle<Map> original_map,
|
|
Handle<Map> transitioned_map)
|
|
: original_map_(original_map),
|
|
transitioned_map_(transitioned_map) {
|
|
SetOperandAt(0, object);
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kChangesElementsKind);
|
|
SetGVNFlag(kChangesElementsPointer);
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* object() { return OperandAt(0); }
|
|
Handle<Map> original_map() { return original_map_; }
|
|
Handle<Map> transitioned_map() { return transitioned_map_; }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
|
|
return original_map_.is_identical_to(instr->original_map()) &&
|
|
transitioned_map_.is_identical_to(instr->transitioned_map());
|
|
}
|
|
|
|
private:
|
|
Handle<Map> original_map_;
|
|
Handle<Map> transitioned_map_;
|
|
};
|
|
|
|
|
|
class HStringAdd: public HBinaryOperation {
|
|
public:
|
|
HStringAdd(HValue* context, HValue* left, HValue* right)
|
|
: HBinaryOperation(context, left, right) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnMaps);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual HType CalculateInferredType() {
|
|
return HType::String();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StringAdd)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
};
|
|
|
|
|
|
class HStringCharCodeAt: public HTemplateInstruction<3> {
|
|
public:
|
|
HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, string);
|
|
SetOperandAt(2, index);
|
|
set_representation(Representation::Integer32());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnMaps);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
// The index is supposed to be Integer32.
|
|
return index == 2
|
|
? Representation::Integer32()
|
|
: Representation::Tagged();
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* string() { return OperandAt(1); }
|
|
HValue* index() { return OperandAt(2); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
|
|
virtual Range* InferRange(Zone* zone) {
|
|
return new(zone) Range(0, String::kMaxUtf16CodeUnit);
|
|
}
|
|
};
|
|
|
|
|
|
class HStringCharFromCode: public HTemplateInstruction<2> {
|
|
public:
|
|
HStringCharFromCode(HValue* context, HValue* char_code) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, char_code);
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return index == 0
|
|
? Representation::Tagged()
|
|
: Representation::Integer32();
|
|
}
|
|
virtual HType CalculateInferredType();
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* value() { return OperandAt(1); }
|
|
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
|
|
};
|
|
|
|
|
|
class HStringLength: public HUnaryOperation {
|
|
public:
|
|
explicit HStringLength(HValue* string) : HUnaryOperation(string) {
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnMaps);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual HType CalculateInferredType() {
|
|
STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
|
|
return HType::Smi();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StringLength)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) { return true; }
|
|
|
|
virtual Range* InferRange(Zone* zone) {
|
|
return new(zone) Range(0, String::kMaxLength);
|
|
}
|
|
};
|
|
|
|
|
|
class HAllocateObject: public HTemplateInstruction<1> {
|
|
public:
|
|
HAllocateObject(HValue* context, Handle<JSFunction> constructor)
|
|
: constructor_(constructor) {
|
|
SetOperandAt(0, context);
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
Handle<JSFunction> constructor() { return constructor_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(AllocateObject)
|
|
|
|
private:
|
|
Handle<JSFunction> constructor_;
|
|
};
|
|
|
|
|
|
template <int V>
|
|
class HMaterializedLiteral: public HTemplateInstruction<V> {
|
|
public:
|
|
HMaterializedLiteral<V>(int index, int depth)
|
|
: literal_index_(index), depth_(depth) {
|
|
this->set_representation(Representation::Tagged());
|
|
}
|
|
|
|
int literal_index() const { return literal_index_; }
|
|
int depth() const { return depth_; }
|
|
|
|
private:
|
|
int literal_index_;
|
|
int depth_;
|
|
};
|
|
|
|
|
|
class HFastLiteral: public HMaterializedLiteral<1> {
|
|
public:
|
|
HFastLiteral(HValue* context,
|
|
Handle<JSObject> boilerplate,
|
|
int total_size,
|
|
int literal_index,
|
|
int depth)
|
|
: HMaterializedLiteral<1>(literal_index, depth),
|
|
boilerplate_(boilerplate),
|
|
total_size_(total_size) {
|
|
SetOperandAt(0, context);
|
|
}
|
|
|
|
// Maximum depth and total number of elements and properties for literal
|
|
// graphs to be considered for fast deep-copying.
|
|
static const int kMaxLiteralDepth = 3;
|
|
static const int kMaxLiteralProperties = 8;
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
Handle<JSObject> boilerplate() const { return boilerplate_; }
|
|
int total_size() const { return total_size_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(FastLiteral)
|
|
|
|
private:
|
|
Handle<JSObject> boilerplate_;
|
|
int total_size_;
|
|
};
|
|
|
|
|
|
class HArrayLiteral: public HMaterializedLiteral<1> {
|
|
public:
|
|
HArrayLiteral(HValue* context,
|
|
Handle<HeapObject> boilerplate_object,
|
|
int length,
|
|
int literal_index,
|
|
int depth)
|
|
: HMaterializedLiteral<1>(literal_index, depth),
|
|
length_(length),
|
|
boilerplate_object_(boilerplate_object) {
|
|
SetOperandAt(0, context);
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
ElementsKind boilerplate_elements_kind() const {
|
|
if (!boilerplate_object_->IsJSObject()) {
|
|
return FAST_ELEMENTS;
|
|
}
|
|
return Handle<JSObject>::cast(boilerplate_object_)->GetElementsKind();
|
|
}
|
|
Handle<HeapObject> boilerplate_object() const { return boilerplate_object_; }
|
|
int length() const { return length_; }
|
|
|
|
bool IsCopyOnWrite() const;
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral)
|
|
|
|
private:
|
|
int length_;
|
|
Handle<HeapObject> boilerplate_object_;
|
|
};
|
|
|
|
|
|
class HObjectLiteral: public HMaterializedLiteral<1> {
|
|
public:
|
|
HObjectLiteral(HValue* context,
|
|
Handle<FixedArray> constant_properties,
|
|
bool fast_elements,
|
|
int literal_index,
|
|
int depth,
|
|
bool has_function)
|
|
: HMaterializedLiteral<1>(literal_index, depth),
|
|
constant_properties_(constant_properties),
|
|
fast_elements_(fast_elements),
|
|
has_function_(has_function) {
|
|
SetOperandAt(0, context);
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
Handle<FixedArray> constant_properties() const {
|
|
return constant_properties_;
|
|
}
|
|
bool fast_elements() const { return fast_elements_; }
|
|
bool has_function() const { return has_function_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral)
|
|
|
|
private:
|
|
Handle<FixedArray> constant_properties_;
|
|
bool fast_elements_;
|
|
bool has_function_;
|
|
};
|
|
|
|
|
|
class HRegExpLiteral: public HMaterializedLiteral<1> {
|
|
public:
|
|
HRegExpLiteral(HValue* context,
|
|
Handle<String> pattern,
|
|
Handle<String> flags,
|
|
int literal_index)
|
|
: HMaterializedLiteral<1>(literal_index, 0),
|
|
pattern_(pattern),
|
|
flags_(flags) {
|
|
SetOperandAt(0, context);
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
Handle<String> pattern() { return pattern_; }
|
|
Handle<String> flags() { return flags_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
|
|
|
|
private:
|
|
Handle<String> pattern_;
|
|
Handle<String> flags_;
|
|
};
|
|
|
|
|
|
class HFunctionLiteral: public HTemplateInstruction<1> {
|
|
public:
|
|
HFunctionLiteral(HValue* context,
|
|
Handle<SharedFunctionInfo> shared,
|
|
bool pretenure)
|
|
: shared_info_(shared), pretenure_(pretenure) {
|
|
SetOperandAt(0, context);
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
|
|
|
|
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
|
|
bool pretenure() const { return pretenure_; }
|
|
|
|
private:
|
|
Handle<SharedFunctionInfo> shared_info_;
|
|
bool pretenure_;
|
|
};
|
|
|
|
|
|
class HTypeof: public HTemplateInstruction<2> {
|
|
public:
|
|
explicit HTypeof(HValue* context, HValue* value) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, value);
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* value() { return OperandAt(1); }
|
|
|
|
virtual HValue* Canonicalize();
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Typeof)
|
|
};
|
|
|
|
|
|
class HToFastProperties: public HUnaryOperation {
|
|
public:
|
|
explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
|
|
// This instruction is not marked as having side effects, but
|
|
// changes the map of the input operand. Use it only when creating
|
|
// object literals.
|
|
ASSERT(value->IsObjectLiteral() || value->IsFastLiteral());
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
|
|
};
|
|
|
|
|
|
class HValueOf: public HUnaryOperation {
|
|
public:
|
|
explicit HValueOf(HValue* value) : HUnaryOperation(value) {
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ValueOf)
|
|
};
|
|
|
|
|
|
class HDateField: public HUnaryOperation {
|
|
public:
|
|
HDateField(HValue* date, Smi* index)
|
|
: HUnaryOperation(date), index_(index) {
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
Smi* index() const { return index_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(DateField)
|
|
|
|
private:
|
|
Smi* index_;
|
|
};
|
|
|
|
|
|
class HDeleteProperty: public HBinaryOperation {
|
|
public:
|
|
HDeleteProperty(HValue* context, HValue* obj, HValue* key)
|
|
: HBinaryOperation(context, obj, key) {
|
|
set_representation(Representation::Tagged());
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual HType CalculateInferredType();
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(DeleteProperty)
|
|
|
|
HValue* object() { return left(); }
|
|
HValue* key() { return right(); }
|
|
};
|
|
|
|
|
|
class HIn: public HTemplateInstruction<3> {
|
|
public:
|
|
HIn(HValue* context, HValue* key, HValue* object) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, key);
|
|
SetOperandAt(2, object);
|
|
set_representation(Representation::Tagged());
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* key() { return OperandAt(1); }
|
|
HValue* object() { return OperandAt(2); }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual HType CalculateInferredType() {
|
|
return HType::Boolean();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(In)
|
|
};
|
|
|
|
|
|
class HCheckMapValue: public HTemplateInstruction<2> {
|
|
public:
|
|
HCheckMapValue(HValue* value,
|
|
HValue* map) {
|
|
SetOperandAt(0, value);
|
|
SetOperandAt(1, map);
|
|
set_representation(Representation::Tagged());
|
|
SetFlag(kUseGVN);
|
|
SetGVNFlag(kDependsOnMaps);
|
|
SetGVNFlag(kDependsOnElementsKind);
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual HType CalculateInferredType() {
|
|
return HType::Tagged();
|
|
}
|
|
|
|
HValue* value() { return OperandAt(0); }
|
|
HValue* map() { return OperandAt(1); }
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckMapValue)
|
|
|
|
protected:
|
|
virtual bool DataEquals(HValue* other) {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
|
|
class HForInPrepareMap : public HTemplateInstruction<2> {
|
|
public:
|
|
HForInPrepareMap(HValue* context,
|
|
HValue* object) {
|
|
SetOperandAt(0, context);
|
|
SetOperandAt(1, object);
|
|
set_representation(Representation::Tagged());
|
|
SetAllSideEffects();
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* context() { return OperandAt(0); }
|
|
HValue* enumerable() { return OperandAt(1); }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual HType CalculateInferredType() {
|
|
return HType::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap);
|
|
};
|
|
|
|
|
|
class HForInCacheArray : public HTemplateInstruction<2> {
|
|
public:
|
|
HForInCacheArray(HValue* enumerable,
|
|
HValue* keys,
|
|
int idx) : idx_(idx) {
|
|
SetOperandAt(0, enumerable);
|
|
SetOperandAt(1, keys);
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* enumerable() { return OperandAt(0); }
|
|
HValue* map() { return OperandAt(1); }
|
|
int idx() { return idx_; }
|
|
|
|
HForInCacheArray* index_cache() {
|
|
return index_cache_;
|
|
}
|
|
|
|
void set_index_cache(HForInCacheArray* index_cache) {
|
|
index_cache_ = index_cache;
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual HType CalculateInferredType() {
|
|
return HType::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray);
|
|
|
|
private:
|
|
int idx_;
|
|
HForInCacheArray* index_cache_;
|
|
};
|
|
|
|
|
|
class HLoadFieldByIndex : public HTemplateInstruction<2> {
|
|
public:
|
|
HLoadFieldByIndex(HValue* object,
|
|
HValue* index) {
|
|
SetOperandAt(0, object);
|
|
SetOperandAt(1, index);
|
|
set_representation(Representation::Tagged());
|
|
}
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) {
|
|
return Representation::Tagged();
|
|
}
|
|
|
|
HValue* object() { return OperandAt(0); }
|
|
HValue* index() { return OperandAt(1); }
|
|
|
|
virtual void PrintDataTo(StringStream* stream);
|
|
|
|
virtual HType CalculateInferredType() {
|
|
return HType::Tagged();
|
|
}
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
|
|
};
|
|
|
|
|
|
#undef DECLARE_INSTRUCTION
|
|
#undef DECLARE_CONCRETE_INSTRUCTION
|
|
|
|
} } // namespace v8::internal
|
|
|
|
#endif // V8_HYDROGEN_INSTRUCTIONS_H_
|