2010-12-07 11:31:57 +00:00
|
|
|
// Copyright 2010 the V8 project authors. All rights reserved.
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are
|
|
|
|
// met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer.
|
|
|
|
// * Redistributions in binary form must reproduce the above
|
|
|
|
// copyright notice, this list of conditions and the following
|
|
|
|
// disclaimer in the documentation and/or other materials provided
|
|
|
|
// with the distribution.
|
|
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
|
|
// contributors may be used to endorse or promote products derived
|
|
|
|
// from this software without specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
#ifndef V8_HYDROGEN_INSTRUCTIONS_H_
|
|
|
|
#define V8_HYDROGEN_INSTRUCTIONS_H_
|
|
|
|
|
|
|
|
#include "v8.h"
|
|
|
|
#include "code-stubs.h"
|
|
|
|
#include "string-stream.h"
|
|
|
|
#include "zone.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
// Forward declarations.
|
|
|
|
class HBasicBlock;
|
|
|
|
class HEnvironment;
|
|
|
|
class HInstruction;
|
|
|
|
class HLoopInformation;
|
|
|
|
class HValue;
|
|
|
|
class LInstruction;
|
|
|
|
class LChunkBuilder;
|
|
|
|
|
|
|
|
|
|
|
|
// Type hierarchy:
|
|
|
|
//
|
|
|
|
// HValue
|
|
|
|
// HInstruction
|
|
|
|
// HAccessArgumentsAt
|
|
|
|
// HApplyArguments
|
|
|
|
// HArgumentsElements
|
|
|
|
// HArgumentsLength
|
|
|
|
// HArgumentsObject
|
|
|
|
// HBinaryOperation
|
|
|
|
// HArithmeticBinaryOperation
|
|
|
|
// HAdd
|
|
|
|
// HDiv
|
|
|
|
// HMod
|
|
|
|
// HMul
|
|
|
|
// HSub
|
|
|
|
// HBitwiseBinaryOperation
|
|
|
|
// HBitAnd
|
|
|
|
// HBitOr
|
|
|
|
// HBitXor
|
|
|
|
// HSar
|
|
|
|
// HShl
|
|
|
|
// HShr
|
|
|
|
// HBoundsCheck
|
|
|
|
// HCompare
|
|
|
|
// HCompareJSObjectEq
|
|
|
|
// HInstanceOf
|
2011-01-05 11:17:37 +00:00
|
|
|
// HInstanceOfKnownGlobal
|
2010-12-07 11:31:57 +00:00
|
|
|
// HLoadKeyed
|
|
|
|
// HLoadKeyedFastElement
|
|
|
|
// HLoadKeyedGeneric
|
2010-12-08 14:32:40 +00:00
|
|
|
// HPower
|
2010-12-07 11:31:57 +00:00
|
|
|
// HStoreNamed
|
|
|
|
// HStoreNamedField
|
|
|
|
// HStoreNamedGeneric
|
|
|
|
// HBlockEntry
|
|
|
|
// HCall
|
|
|
|
// HCallConstantFunction
|
|
|
|
// HCallFunction
|
|
|
|
// HCallGlobal
|
|
|
|
// HCallKeyed
|
|
|
|
// HCallKnownGlobal
|
|
|
|
// HCallNamed
|
|
|
|
// HCallNew
|
|
|
|
// HCallRuntime
|
|
|
|
// HCallStub
|
|
|
|
// HConstant
|
|
|
|
// HControlInstruction
|
2010-12-16 13:13:36 +00:00
|
|
|
// HDeoptimize
|
2010-12-07 11:31:57 +00:00
|
|
|
// HGoto
|
|
|
|
// HUnaryControlInstruction
|
|
|
|
// HBranch
|
|
|
|
// HCompareMapAndBranch
|
|
|
|
// HReturn
|
|
|
|
// HThrow
|
|
|
|
// HEnterInlined
|
|
|
|
// HFunctionLiteral
|
|
|
|
// HGlobalObject
|
|
|
|
// HGlobalReceiver
|
|
|
|
// HLeaveInlined
|
|
|
|
// HLoadGlobal
|
|
|
|
// HMaterializedLiteral
|
|
|
|
// HArrayLiteral
|
|
|
|
// HObjectLiteral
|
|
|
|
// HRegExpLiteral
|
|
|
|
// HOsrEntry
|
|
|
|
// HParameter
|
|
|
|
// HSimulate
|
|
|
|
// HStackCheck
|
|
|
|
// HStoreKeyed
|
|
|
|
// HStoreKeyedFastElement
|
|
|
|
// HStoreKeyedGeneric
|
|
|
|
// HUnaryOperation
|
|
|
|
// HBitNot
|
|
|
|
// HChange
|
|
|
|
// HCheckFunction
|
|
|
|
// HCheckInstanceType
|
|
|
|
// HCheckMap
|
|
|
|
// HCheckNonSmi
|
|
|
|
// HCheckPrototypeMaps
|
|
|
|
// HCheckSmi
|
|
|
|
// HDeleteProperty
|
2010-12-30 19:30:42 +00:00
|
|
|
// HFixedArrayLength
|
|
|
|
// HJSArrayLength
|
2010-12-07 11:31:57 +00:00
|
|
|
// HLoadElements
|
|
|
|
// HTypeofIs
|
|
|
|
// HLoadNamedField
|
2010-12-22 15:43:32 +00:00
|
|
|
// HLoadNamedGeneric
|
|
|
|
// HLoadFunctionPrototype
|
2010-12-07 11:31:57 +00:00
|
|
|
// HPushArgument
|
|
|
|
// HTypeof
|
|
|
|
// HUnaryMathOperation
|
|
|
|
// HUnaryPredicate
|
|
|
|
// HClassOfTest
|
|
|
|
// HHasCachedArrayIndex
|
|
|
|
// HHasInstanceType
|
|
|
|
// HIsNull
|
2010-12-15 12:32:19 +00:00
|
|
|
// HIsObject
|
2010-12-07 11:31:57 +00:00
|
|
|
// HIsSmi
|
|
|
|
// HValueOf
|
|
|
|
// HUnknownOSRValue
|
|
|
|
// HPhi
|
|
|
|
|
|
|
|
#define HYDROGEN_ALL_INSTRUCTION_LIST(V) \
|
|
|
|
V(ArithmeticBinaryOperation) \
|
|
|
|
V(BinaryOperation) \
|
|
|
|
V(BitwiseBinaryOperation) \
|
|
|
|
V(Call) \
|
|
|
|
V(ControlInstruction) \
|
|
|
|
V(Instruction) \
|
|
|
|
V(LoadKeyed) \
|
|
|
|
V(MaterializedLiteral) \
|
|
|
|
V(Phi) \
|
|
|
|
V(StoreKeyed) \
|
|
|
|
V(StoreNamed) \
|
|
|
|
V(UnaryControlInstruction) \
|
|
|
|
V(UnaryOperation) \
|
|
|
|
HYDROGEN_CONCRETE_INSTRUCTION_LIST(V)
|
|
|
|
|
|
|
|
|
|
|
|
#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
|
|
|
|
V(AccessArgumentsAt) \
|
|
|
|
V(Add) \
|
|
|
|
V(ApplyArguments) \
|
|
|
|
V(ArgumentsElements) \
|
|
|
|
V(ArgumentsLength) \
|
|
|
|
V(ArgumentsObject) \
|
|
|
|
V(ArrayLiteral) \
|
|
|
|
V(BitAnd) \
|
|
|
|
V(BitNot) \
|
|
|
|
V(BitOr) \
|
|
|
|
V(BitXor) \
|
|
|
|
V(BlockEntry) \
|
|
|
|
V(BoundsCheck) \
|
|
|
|
V(Branch) \
|
|
|
|
V(CallConstantFunction) \
|
|
|
|
V(CallFunction) \
|
|
|
|
V(CallGlobal) \
|
|
|
|
V(CallKeyed) \
|
|
|
|
V(CallKnownGlobal) \
|
|
|
|
V(CallNamed) \
|
|
|
|
V(CallNew) \
|
|
|
|
V(CallRuntime) \
|
|
|
|
V(CallStub) \
|
|
|
|
V(Change) \
|
|
|
|
V(CheckFunction) \
|
|
|
|
V(CheckInstanceType) \
|
|
|
|
V(CheckMap) \
|
|
|
|
V(CheckNonSmi) \
|
|
|
|
V(CheckPrototypeMaps) \
|
|
|
|
V(CheckSmi) \
|
|
|
|
V(Compare) \
|
|
|
|
V(CompareJSObjectEq) \
|
|
|
|
V(CompareMapAndBranch) \
|
|
|
|
V(Constant) \
|
|
|
|
V(DeleteProperty) \
|
|
|
|
V(Deoptimize) \
|
|
|
|
V(Div) \
|
|
|
|
V(EnterInlined) \
|
2010-12-30 19:30:42 +00:00
|
|
|
V(FixedArrayLength) \
|
2010-12-07 11:31:57 +00:00
|
|
|
V(FunctionLiteral) \
|
|
|
|
V(GlobalObject) \
|
|
|
|
V(GlobalReceiver) \
|
|
|
|
V(Goto) \
|
|
|
|
V(InstanceOf) \
|
2011-01-05 11:17:37 +00:00
|
|
|
V(InstanceOfKnownGlobal) \
|
2010-12-07 11:31:57 +00:00
|
|
|
V(IsNull) \
|
2010-12-15 12:32:19 +00:00
|
|
|
V(IsObject) \
|
2010-12-07 11:31:57 +00:00
|
|
|
V(IsSmi) \
|
|
|
|
V(HasInstanceType) \
|
|
|
|
V(HasCachedArrayIndex) \
|
2010-12-30 19:30:42 +00:00
|
|
|
V(JSArrayLength) \
|
2010-12-07 11:31:57 +00:00
|
|
|
V(ClassOfTest) \
|
|
|
|
V(LeaveInlined) \
|
|
|
|
V(LoadElements) \
|
|
|
|
V(LoadGlobal) \
|
|
|
|
V(LoadKeyedFastElement) \
|
|
|
|
V(LoadKeyedGeneric) \
|
|
|
|
V(LoadNamedField) \
|
|
|
|
V(LoadNamedGeneric) \
|
2010-12-22 15:43:32 +00:00
|
|
|
V(LoadFunctionPrototype) \
|
2010-12-07 11:31:57 +00:00
|
|
|
V(Mod) \
|
|
|
|
V(Mul) \
|
|
|
|
V(ObjectLiteral) \
|
|
|
|
V(OsrEntry) \
|
|
|
|
V(Parameter) \
|
2010-12-08 14:32:40 +00:00
|
|
|
V(Power) \
|
2010-12-07 11:31:57 +00:00
|
|
|
V(PushArgument) \
|
|
|
|
V(RegExpLiteral) \
|
|
|
|
V(Return) \
|
|
|
|
V(Sar) \
|
|
|
|
V(Shl) \
|
|
|
|
V(Shr) \
|
|
|
|
V(Simulate) \
|
|
|
|
V(StackCheck) \
|
|
|
|
V(StoreGlobal) \
|
|
|
|
V(StoreKeyedFastElement) \
|
|
|
|
V(StoreKeyedGeneric) \
|
|
|
|
V(StoreNamedField) \
|
|
|
|
V(StoreNamedGeneric) \
|
|
|
|
V(Sub) \
|
|
|
|
V(Throw) \
|
|
|
|
V(Typeof) \
|
|
|
|
V(TypeofIs) \
|
|
|
|
V(UnaryMathOperation) \
|
|
|
|
V(UnknownOSRValue) \
|
|
|
|
V(ValueOf)
|
|
|
|
|
|
|
|
#define GVN_FLAG_LIST(V) \
|
|
|
|
V(Calls) \
|
|
|
|
V(InobjectFields) \
|
|
|
|
V(BackingStoreFields) \
|
|
|
|
V(ArrayElements) \
|
|
|
|
V(GlobalVars) \
|
|
|
|
V(Maps) \
|
|
|
|
V(ArrayLengths) \
|
2010-12-22 15:43:32 +00:00
|
|
|
V(FunctionPrototypes) \
|
2010-12-07 11:31:57 +00:00
|
|
|
V(OsrEntries)
|
|
|
|
|
|
|
|
#define DECLARE_INSTRUCTION(type) \
|
|
|
|
virtual bool Is##type() const { return true; } \
|
|
|
|
static H##type* cast(HValue* value) { \
|
|
|
|
ASSERT(value->Is##type()); \
|
|
|
|
return reinterpret_cast<H##type*>(value); \
|
|
|
|
} \
|
|
|
|
Opcode opcode() const { return HValue::k##type; }
|
|
|
|
|
|
|
|
|
|
|
|
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
|
|
|
|
virtual LInstruction* CompileToLithium(LChunkBuilder* builder); \
|
|
|
|
virtual const char* Mnemonic() const { return mnemonic; } \
|
|
|
|
DECLARE_INSTRUCTION(type)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<int kSize>
|
|
|
|
class HOperandVector : public EmbeddedVector<HValue*, kSize> {
|
|
|
|
public:
|
|
|
|
HOperandVector() : EmbeddedVector<HValue*, kSize>(NULL) { }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Range: public ZoneObject {
|
|
|
|
public:
|
|
|
|
Range() : lower_(kMinInt),
|
|
|
|
upper_(kMaxInt),
|
|
|
|
next_(NULL),
|
|
|
|
can_be_minus_zero_(false) { }
|
|
|
|
|
|
|
|
Range(int32_t lower, int32_t upper)
|
|
|
|
: lower_(lower), upper_(upper), next_(NULL), can_be_minus_zero_(false) { }
|
|
|
|
|
|
|
|
bool IsInSmiRange() const {
|
|
|
|
return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
|
|
|
|
}
|
|
|
|
void KeepOrder();
|
|
|
|
void Verify() const;
|
|
|
|
int32_t upper() const { return upper_; }
|
|
|
|
int32_t lower() const { return lower_; }
|
|
|
|
Range* next() const { return next_; }
|
|
|
|
Range* CopyClearLower() const { return new Range(kMinInt, upper_); }
|
|
|
|
Range* CopyClearUpper() const { return new Range(lower_, kMaxInt); }
|
|
|
|
void ClearLower() { lower_ = kMinInt; }
|
|
|
|
void ClearUpper() { upper_ = kMaxInt; }
|
|
|
|
Range* Copy() const { return new Range(lower_, upper_); }
|
|
|
|
bool IsMostGeneric() const { return lower_ == kMinInt && upper_ == kMaxInt; }
|
|
|
|
int32_t Mask() const;
|
|
|
|
void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
|
|
|
|
bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
|
|
|
|
bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
|
|
|
|
bool CanBeNegative() const { return lower_ < 0; }
|
|
|
|
bool Includes(int value) const {
|
|
|
|
return lower_ <= value && upper_ >= value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sar(int32_t value) {
|
|
|
|
int32_t bits = value & 0x1F;
|
|
|
|
lower_ = lower_ >> bits;
|
|
|
|
upper_ = upper_ >> bits;
|
|
|
|
set_can_be_minus_zero(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Shl(int32_t value) {
|
|
|
|
int32_t bits = value & 0x1F;
|
|
|
|
int old_lower = lower_;
|
|
|
|
int old_upper = upper_;
|
|
|
|
lower_ = lower_ << bits;
|
|
|
|
upper_ = upper_ << bits;
|
|
|
|
if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) {
|
|
|
|
upper_ = kMaxInt;
|
|
|
|
lower_ = kMinInt;
|
|
|
|
}
|
|
|
|
set_can_be_minus_zero(false);
|
|
|
|
}
|
|
|
|
|
2010-12-16 18:01:36 +00:00
|
|
|
// Adds a constant to the lower and upper bound of the range.
|
|
|
|
void AddConstant(int32_t value);
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
void StackUpon(Range* other) {
|
|
|
|
Intersect(other);
|
|
|
|
next_ = other;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Intersect(Range* other) {
|
|
|
|
upper_ = Min(upper_, other->upper_);
|
|
|
|
lower_ = Max(lower_, other->lower_);
|
|
|
|
bool b = CanBeMinusZero() && other->CanBeMinusZero();
|
|
|
|
set_can_be_minus_zero(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Union(Range* other) {
|
|
|
|
upper_ = Max(upper_, other->upper_);
|
|
|
|
lower_ = Min(lower_, other->lower_);
|
|
|
|
bool b = CanBeMinusZero() || other->CanBeMinusZero();
|
|
|
|
set_can_be_minus_zero(b);
|
|
|
|
}
|
|
|
|
|
2010-12-16 18:01:36 +00:00
|
|
|
// Compute a new result range and return true, if the operation
|
|
|
|
// can overflow.
|
2010-12-07 11:31:57 +00:00
|
|
|
bool AddAndCheckOverflow(Range* other);
|
|
|
|
bool SubAndCheckOverflow(Range* other);
|
|
|
|
bool MulAndCheckOverflow(Range* other);
|
|
|
|
|
|
|
|
private:
|
|
|
|
int32_t lower_;
|
|
|
|
int32_t upper_;
|
|
|
|
Range* next_;
|
|
|
|
bool can_be_minus_zero_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Representation {
|
|
|
|
public:
|
|
|
|
enum Kind {
|
|
|
|
kNone,
|
|
|
|
kTagged,
|
|
|
|
kDouble,
|
|
|
|
kInteger32,
|
|
|
|
kNumRepresentations
|
|
|
|
};
|
|
|
|
|
|
|
|
Representation() : kind_(kNone) { }
|
|
|
|
|
|
|
|
static Representation None() { return Representation(kNone); }
|
|
|
|
static Representation Tagged() { return Representation(kTagged); }
|
|
|
|
static Representation Integer32() { return Representation(kInteger32); }
|
|
|
|
static Representation Double() { return Representation(kDouble); }
|
|
|
|
|
|
|
|
bool Equals(const Representation& other) const {
|
|
|
|
return kind_ == other.kind_;
|
|
|
|
}
|
|
|
|
|
|
|
|
Kind kind() const { return kind_; }
|
|
|
|
bool IsNone() const { return kind_ == kNone; }
|
|
|
|
bool IsTagged() const { return kind_ == kTagged; }
|
|
|
|
bool IsInteger32() const { return kind_ == kInteger32; }
|
|
|
|
bool IsDouble() const { return kind_ == kDouble; }
|
|
|
|
bool IsSpecialization() const {
|
|
|
|
return kind_ == kInteger32 || kind_ == kDouble;
|
|
|
|
}
|
|
|
|
const char* Mnemonic() const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
explicit Representation(Kind k) : kind_(k) { }
|
|
|
|
|
|
|
|
Kind kind_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HType {
|
|
|
|
public:
|
|
|
|
HType() : type_(kUninitialized) { }
|
|
|
|
|
|
|
|
static HType Tagged() { return HType(kTagged); }
|
|
|
|
static HType TaggedPrimitive() { return HType(kTaggedPrimitive); }
|
|
|
|
static HType TaggedNumber() { return HType(kTaggedNumber); }
|
|
|
|
static HType Smi() { return HType(kSmi); }
|
|
|
|
static HType HeapNumber() { return HType(kHeapNumber); }
|
|
|
|
static HType String() { return HType(kString); }
|
|
|
|
static HType Boolean() { return HType(kBoolean); }
|
|
|
|
static HType NonPrimitive() { return HType(kNonPrimitive); }
|
|
|
|
static HType JSArray() { return HType(kJSArray); }
|
|
|
|
static HType JSObject() { return HType(kJSObject); }
|
|
|
|
static HType Uninitialized() { return HType(kUninitialized); }
|
|
|
|
|
|
|
|
// Return the weakest (least precise) common type.
|
|
|
|
HType Combine(HType other) {
|
|
|
|
return HType(static_cast<Type>(type_ & other.type_));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Equals(const HType& other) {
|
|
|
|
return type_ == other.type_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsSubtypeOf(const HType& other) {
|
|
|
|
return Combine(other).Equals(other);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsTagged() {
|
|
|
|
ASSERT(type_ != kUninitialized);
|
|
|
|
return ((type_ & kTagged) == kTagged);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsTaggedPrimitive() {
|
|
|
|
ASSERT(type_ != kUninitialized);
|
|
|
|
return ((type_ & kTaggedPrimitive) == kTaggedPrimitive);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsTaggedNumber() {
|
|
|
|
ASSERT(type_ != kUninitialized);
|
|
|
|
return ((type_ & kTaggedNumber) == kTaggedNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsSmi() {
|
|
|
|
ASSERT(type_ != kUninitialized);
|
|
|
|
return ((type_ & kSmi) == kSmi);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsHeapNumber() {
|
|
|
|
ASSERT(type_ != kUninitialized);
|
|
|
|
return ((type_ & kHeapNumber) == kHeapNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsString() {
|
|
|
|
ASSERT(type_ != kUninitialized);
|
|
|
|
return ((type_ & kString) == kString);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsBoolean() {
|
|
|
|
ASSERT(type_ != kUninitialized);
|
|
|
|
return ((type_ & kBoolean) == kBoolean);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsNonPrimitive() {
|
|
|
|
ASSERT(type_ != kUninitialized);
|
|
|
|
return ((type_ & kNonPrimitive) == kNonPrimitive);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsJSArray() {
|
|
|
|
ASSERT(type_ != kUninitialized);
|
|
|
|
return ((type_ & kJSArray) == kJSArray);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsJSObject() {
|
|
|
|
ASSERT(type_ != kUninitialized);
|
|
|
|
return ((type_ & kJSObject) == kJSObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsUninitialized() {
|
|
|
|
return type_ == kUninitialized;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HType TypeFromValue(Handle<Object> value);
|
|
|
|
|
|
|
|
const char* ToString();
|
|
|
|
const char* ToShortString();
|
|
|
|
|
|
|
|
private:
|
|
|
|
enum Type {
|
|
|
|
kTagged = 0x1, // 0000 0000 0000 0001
|
|
|
|
kTaggedPrimitive = 0x5, // 0000 0000 0000 0101
|
|
|
|
kTaggedNumber = 0xd, // 0000 0000 0000 1101
|
|
|
|
kSmi = 0x1d, // 0000 0000 0001 1101
|
|
|
|
kHeapNumber = 0x2d, // 0000 0000 0010 1101
|
|
|
|
kString = 0x45, // 0000 0000 0100 0101
|
|
|
|
kBoolean = 0x85, // 0000 0000 1000 0101
|
|
|
|
kNonPrimitive = 0x101, // 0000 0001 0000 0001
|
|
|
|
kJSObject = 0x301, // 0000 0011 0000 0001
|
|
|
|
kJSArray = 0x701, // 0000 0111 1000 0001
|
|
|
|
kUninitialized = 0x1fff // 0001 1111 1111 1111
|
|
|
|
};
|
|
|
|
|
|
|
|
explicit HType(Type t) : type_(t) { }
|
|
|
|
|
|
|
|
Type type_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HValue: public ZoneObject {
|
|
|
|
public:
|
|
|
|
static const int kNoNumber = -1;
|
|
|
|
|
|
|
|
// There must be one corresponding kDepends flag for every kChanges flag and
|
|
|
|
// the order of the kChanges flags must be exactly the same as of the kDepends
|
|
|
|
// flags.
|
|
|
|
enum Flag {
|
|
|
|
// Declare global value numbering flags.
|
|
|
|
#define DECLARE_DO(type) kChanges##type, kDependsOn##type,
|
|
|
|
GVN_FLAG_LIST(DECLARE_DO)
|
|
|
|
#undef DECLARE_DO
|
|
|
|
kFlexibleRepresentation,
|
|
|
|
kUseGVN,
|
|
|
|
kCanOverflow,
|
|
|
|
kBailoutOnMinusZero,
|
|
|
|
kCanBeDivByZero,
|
|
|
|
kIsArguments,
|
|
|
|
kTruncatingToInt32,
|
|
|
|
kLastFlag = kTruncatingToInt32
|
|
|
|
};
|
|
|
|
|
|
|
|
STATIC_ASSERT(kLastFlag < kBitsPerInt);
|
|
|
|
|
|
|
|
static const int kChangesToDependsFlagsLeftShift = 1;
|
|
|
|
|
|
|
|
static int ChangesFlagsMask() {
|
|
|
|
int result = 0;
|
|
|
|
// Create changes mask.
|
|
|
|
#define DECLARE_DO(type) result |= (1 << kChanges##type);
|
|
|
|
GVN_FLAG_LIST(DECLARE_DO)
|
|
|
|
#undef DECLARE_DO
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int DependsFlagsMask() {
|
|
|
|
return ConvertChangesToDependsFlags(ChangesFlagsMask());
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ConvertChangesToDependsFlags(int flags) {
|
|
|
|
return flags << kChangesToDependsFlagsLeftShift;
|
|
|
|
}
|
|
|
|
|
|
|
|
// A flag mask to mark an instruction as having arbitrary side effects.
|
|
|
|
static int AllSideEffects() {
|
|
|
|
return ChangesFlagsMask() & ~(1 << kChangesOsrEntries);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HValue* cast(HValue* value) { return value; }
|
|
|
|
|
|
|
|
enum Opcode {
|
|
|
|
// Declare a unique enum value for each hydrogen instruction.
|
|
|
|
#define DECLARE_DO(type) k##type,
|
|
|
|
HYDROGEN_ALL_INSTRUCTION_LIST(DECLARE_DO)
|
|
|
|
#undef DECLARE_DO
|
|
|
|
kMaxInstructionClass
|
|
|
|
};
|
|
|
|
|
|
|
|
HValue() : block_(NULL),
|
|
|
|
id_(kNoNumber),
|
|
|
|
uses_(2),
|
|
|
|
type_(HType::Tagged()),
|
|
|
|
range_(NULL),
|
|
|
|
flags_(0) {}
|
|
|
|
virtual ~HValue() {}
|
|
|
|
|
|
|
|
HBasicBlock* block() const { return block_; }
|
|
|
|
void SetBlock(HBasicBlock* block);
|
|
|
|
|
|
|
|
int id() const { return id_; }
|
|
|
|
void set_id(int id) { id_ = id; }
|
|
|
|
|
|
|
|
const ZoneList<HValue*>* uses() const { return &uses_; }
|
|
|
|
|
|
|
|
virtual bool EmitAtUses() const { return false; }
|
|
|
|
Representation representation() const { return representation_; }
|
|
|
|
void ChangeRepresentation(Representation r) {
|
|
|
|
// Representation was already set and is allowed to be changed.
|
|
|
|
ASSERT(!representation_.IsNone());
|
|
|
|
ASSERT(!r.IsNone());
|
|
|
|
ASSERT(CheckFlag(kFlexibleRepresentation));
|
|
|
|
RepresentationChanged(r);
|
|
|
|
representation_ = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
HType type() const { return type_; }
|
|
|
|
void set_type(HType type) {
|
|
|
|
ASSERT(uses_.length() == 0);
|
|
|
|
type_ = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
// An operation needs to override this function iff:
|
|
|
|
// 1) it can produce an int32 output.
|
|
|
|
// 2) the true value of its output can potentially be minus zero.
|
|
|
|
// The implementation must set a flag so that it bails out in the case where
|
|
|
|
// it would otherwise output what should be a minus zero as an int32 zero.
|
|
|
|
// If the operation also exists in a form that takes int32 and outputs int32
|
|
|
|
// then the operation should return its input value so that we can propagate
|
|
|
|
// back. There are two operations that need to propagate back to more than
|
|
|
|
// one input. They are phi and binary add. They always return NULL and
|
|
|
|
// expect the caller to take care of things.
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited) {
|
|
|
|
visited->Add(id());
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool HasSideEffects() const {
|
|
|
|
return (flags_ & AllSideEffects()) != 0;
|
|
|
|
}
|
|
|
|
bool IsDefinedAfter(HBasicBlock* other) const;
|
|
|
|
|
|
|
|
// Operands.
|
|
|
|
virtual int OperandCount() const { return 0; }
|
|
|
|
virtual HValue* OperandAt(int index) const {
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
void SetOperandAt(int index, HValue* value);
|
|
|
|
|
|
|
|
int LookupOperandIndex(int occurrence_index, HValue* op) const;
|
|
|
|
bool UsesMultipleTimes(HValue* op) const;
|
|
|
|
|
|
|
|
void ReplaceAndDelete(HValue* other);
|
|
|
|
void ReplaceValue(HValue* other);
|
|
|
|
void ReplaceAtUse(HValue* use, HValue* other);
|
|
|
|
void ReplaceFirstAtUse(HValue* use, HValue* other, Representation r);
|
|
|
|
bool HasNoUses() const { return uses_.is_empty(); }
|
|
|
|
void ClearOperands();
|
|
|
|
void Delete();
|
|
|
|
|
|
|
|
int flags() const { return flags_; }
|
|
|
|
void SetFlagMask(int mask) { flags_ |= mask; }
|
|
|
|
void SetFlag(Flag f) { SetFlagMask(1 << f); }
|
|
|
|
void ClearFlagMask(int mask) { flags_ &= ~mask; }
|
|
|
|
void ClearFlag(Flag f) { ClearFlagMask(1 << f); }
|
|
|
|
bool CheckFlag(Flag f) const { return CheckFlagMask(1 << f); }
|
|
|
|
bool CheckFlagMask(int mask) const { return (flags_ & mask) != 0; }
|
|
|
|
|
|
|
|
Range* range() const { return range_; }
|
|
|
|
bool HasRange() const { return range_ != NULL; }
|
|
|
|
void AddNewRange(Range* r);
|
|
|
|
void RemoveLastAddedRange();
|
|
|
|
void ComputeInitialRange();
|
|
|
|
|
|
|
|
// Representation helpers.
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::None();
|
|
|
|
}
|
|
|
|
virtual Representation InferredRepresentation() const {
|
|
|
|
return representation();
|
|
|
|
}
|
|
|
|
|
|
|
|
// This gives the instruction an opportunity to replace itself with an
|
|
|
|
// instruction that does the same in some better way. To replace an
|
|
|
|
// instruction with a new one, first add the new instruction to the graph,
|
|
|
|
// then return it. Return NULL to have the instruction deleted.
|
|
|
|
virtual HValue* Canonicalize() { return this; }
|
|
|
|
|
|
|
|
// Declare virtual type testers.
|
|
|
|
#define DECLARE_DO(type) virtual bool Is##type() const { return false; }
|
|
|
|
HYDROGEN_ALL_INSTRUCTION_LIST(DECLARE_DO)
|
|
|
|
#undef DECLARE_DO
|
|
|
|
|
|
|
|
bool Equals(HValue* other) const;
|
|
|
|
virtual intptr_t Hashcode() const;
|
|
|
|
|
|
|
|
// Printing support.
|
|
|
|
virtual void PrintTo(StringStream* stream) const = 0;
|
|
|
|
void PrintNameTo(StringStream* stream);
|
|
|
|
static void PrintTypeTo(HType type, StringStream* stream);
|
|
|
|
|
|
|
|
virtual const char* Mnemonic() const = 0;
|
|
|
|
virtual Opcode opcode() const = 0;
|
|
|
|
|
|
|
|
// Updated the inferred type of this instruction and returns true if
|
|
|
|
// it has changed.
|
|
|
|
bool UpdateInferredType();
|
|
|
|
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
// Helper for type conversions used by normal and phi instructions.
|
|
|
|
void InsertInputConversion(HInstruction* previous, int index, HType type);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const { return true; }
|
|
|
|
virtual void RepresentationChanged(Representation to) { }
|
|
|
|
virtual Range* InferRange();
|
|
|
|
virtual void DeleteFromGraph() = 0;
|
|
|
|
virtual void InternalSetOperandAt(int index, HValue* value) { UNREACHABLE(); }
|
|
|
|
void clear_block() {
|
|
|
|
ASSERT(block_ != NULL);
|
|
|
|
block_ = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_representation(Representation r) {
|
|
|
|
// Representation is set-once.
|
|
|
|
ASSERT(representation_.IsNone() && !r.IsNone());
|
|
|
|
representation_ = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void InternalReplaceAtUse(HValue* use, HValue* other);
|
|
|
|
void RegisterUse(int index, HValue* new_value);
|
|
|
|
|
|
|
|
HBasicBlock* block_;
|
|
|
|
|
|
|
|
// The id of this instruction in the hydrogen graph, assigned when first
|
|
|
|
// added to the graph. Reflects creation order.
|
|
|
|
int id_;
|
|
|
|
|
|
|
|
Representation representation_;
|
|
|
|
ZoneList<HValue*> uses_;
|
|
|
|
HType type_;
|
|
|
|
Range* range_;
|
|
|
|
int flags_;
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(HValue);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HInstruction: public HValue {
|
|
|
|
public:
|
|
|
|
HInstruction* next() const { return next_; }
|
|
|
|
HInstruction* previous() const { return previous_; }
|
|
|
|
|
|
|
|
void PrintTo(StringStream* stream) const;
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const {}
|
|
|
|
|
|
|
|
bool IsLinked() const { return block() != NULL; }
|
|
|
|
void Unlink();
|
|
|
|
void InsertBefore(HInstruction* next);
|
|
|
|
void InsertAfter(HInstruction* previous);
|
|
|
|
|
|
|
|
int position() const { return position_; }
|
|
|
|
bool has_position() const { return position_ != RelocInfo::kNoPosition; }
|
|
|
|
void set_position(int position) { position_ = position; }
|
|
|
|
|
|
|
|
virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(Instruction)
|
|
|
|
|
|
|
|
protected:
|
|
|
|
HInstruction()
|
|
|
|
: next_(NULL),
|
|
|
|
previous_(NULL),
|
|
|
|
position_(RelocInfo::kNoPosition) {
|
|
|
|
SetFlag(kDependsOnOsrEntries);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void DeleteFromGraph() { Unlink(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
void InitializeAsFirst(HBasicBlock* block) {
|
|
|
|
ASSERT(!IsLinked());
|
|
|
|
SetBlock(block);
|
|
|
|
}
|
|
|
|
|
|
|
|
HInstruction* next_;
|
|
|
|
HInstruction* previous_;
|
|
|
|
int position_;
|
|
|
|
|
|
|
|
friend class HBasicBlock;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HBlockEntry: public HInstruction {
|
|
|
|
public:
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(BlockEntry, "block_entry")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HControlInstruction: public HInstruction {
|
|
|
|
public:
|
|
|
|
virtual HBasicBlock* FirstSuccessor() const { return NULL; }
|
|
|
|
virtual HBasicBlock* SecondSuccessor() const { return NULL; }
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(ControlInstruction)
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HDeoptimize: public HControlInstruction {
|
|
|
|
public:
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HGoto: public HControlInstruction {
|
|
|
|
public:
|
|
|
|
explicit HGoto(HBasicBlock* destination)
|
|
|
|
: destination_(destination),
|
|
|
|
include_stack_check_(false) {}
|
|
|
|
|
|
|
|
virtual HBasicBlock* FirstSuccessor() const { return destination_; }
|
|
|
|
void set_include_stack_check(bool include_stack_check) {
|
|
|
|
include_stack_check_ = include_stack_check;
|
|
|
|
}
|
|
|
|
bool include_stack_check() const { return include_stack_check_; }
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
|
|
|
|
|
|
|
|
private:
|
|
|
|
HBasicBlock* destination_;
|
|
|
|
bool include_stack_check_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HUnaryControlInstruction: public HControlInstruction {
|
|
|
|
public:
|
|
|
|
explicit HUnaryControlInstruction(HValue* value) {
|
|
|
|
SetOperandAt(0, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
HValue* value() const { return OperandAt(0); }
|
|
|
|
virtual int OperandCount() const { return 1; }
|
|
|
|
virtual HValue* OperandAt(int index) const { return operands_[index]; }
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(UnaryControlInstruction)
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void InternalSetOperandAt(int index, HValue* value) {
|
|
|
|
operands_[index] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
HOperandVector<1> operands_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HBranch: public HUnaryControlInstruction {
|
|
|
|
public:
|
|
|
|
HBranch(HBasicBlock* true_destination,
|
|
|
|
HBasicBlock* false_destination,
|
|
|
|
HValue* boolean_value)
|
|
|
|
: HUnaryControlInstruction(boolean_value),
|
|
|
|
true_destination_(true_destination),
|
|
|
|
false_destination_(false_destination) {
|
|
|
|
ASSERT(true_destination != NULL && false_destination != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::None();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
|
|
|
|
virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
|
|
|
|
|
|
|
|
private:
|
|
|
|
HBasicBlock* true_destination_;
|
|
|
|
HBasicBlock* false_destination_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCompareMapAndBranch: public HUnaryControlInstruction {
|
|
|
|
public:
|
|
|
|
HCompareMapAndBranch(HValue* result,
|
|
|
|
Handle<Map> map,
|
|
|
|
HBasicBlock* true_destination,
|
|
|
|
HBasicBlock* false_destination)
|
|
|
|
: HUnaryControlInstruction(result),
|
|
|
|
map_(map),
|
|
|
|
true_destination_(true_destination),
|
|
|
|
false_destination_(false_destination) {
|
|
|
|
ASSERT(true_destination != NULL);
|
|
|
|
ASSERT(false_destination != NULL);
|
|
|
|
ASSERT(!map.is_null());
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
|
|
|
|
virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
|
|
|
|
|
2011-01-04 13:02:51 +00:00
|
|
|
HBasicBlock* true_destination() const { return true_destination_; }
|
|
|
|
HBasicBlock* false_destination() const { return false_destination_; }
|
|
|
|
|
2010-12-17 13:44:19 +00:00
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
Handle<Map> map() const { return map_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CompareMapAndBranch, "compare_map_and_branch")
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<Map> map_;
|
|
|
|
HBasicBlock* true_destination_;
|
|
|
|
HBasicBlock* false_destination_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HReturn: public HUnaryControlInstruction {
|
|
|
|
public:
|
|
|
|
explicit HReturn(HValue* result) : HUnaryControlInstruction(result) { }
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Return, "return")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HThrow: public HUnaryControlInstruction {
|
|
|
|
public:
|
|
|
|
explicit HThrow(HValue* value) : HUnaryControlInstruction(value) { }
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Throw, "throw")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HUnaryOperation: public HInstruction {
|
|
|
|
public:
|
|
|
|
explicit HUnaryOperation(HValue* value) {
|
|
|
|
SetOperandAt(0, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
HValue* value() const { return OperandAt(0); }
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
virtual int OperandCount() const { return 1; }
|
|
|
|
virtual HValue* OperandAt(int index) const { return operands_[index]; }
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(UnaryOperation)
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void InternalSetOperandAt(int index, HValue* value) {
|
|
|
|
operands_[index] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
HOperandVector<1> operands_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HChange: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
HChange(HValue* value,
|
|
|
|
Representation from,
|
|
|
|
Representation to)
|
|
|
|
: HUnaryOperation(value), from_(from), to_(to) {
|
|
|
|
ASSERT(!from.IsNone() && !to.IsNone());
|
|
|
|
ASSERT(!from.Equals(to));
|
|
|
|
set_representation(to);
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
|
|
|
|
if (from.IsInteger32() && to.IsTagged() && value->range() != NULL &&
|
|
|
|
value->range()->IsInSmiRange()) {
|
|
|
|
set_type(HType::Smi());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
|
|
|
|
Representation from() const { return from_; }
|
|
|
|
Representation to() const { return to_; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return from_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CanTruncateToInt32() const {
|
|
|
|
for (int i = 0; i < uses()->length(); ++i) {
|
|
|
|
if (!uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Change,
|
|
|
|
CanTruncateToInt32() ? "truncate" : "change")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
if (!other->IsChange()) return false;
|
|
|
|
HChange* change = HChange::cast(other);
|
|
|
|
return value() == change->value()
|
|
|
|
&& to().Equals(change->to())
|
|
|
|
&& CanTruncateToInt32() == change->CanTruncateToInt32();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Representation from_;
|
|
|
|
Representation to_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HSimulate: public HInstruction {
|
|
|
|
public:
|
2011-01-03 16:57:46 +00:00
|
|
|
HSimulate(int ast_id, int pop_count, int environment_length)
|
2010-12-07 11:31:57 +00:00
|
|
|
: ast_id_(ast_id),
|
|
|
|
pop_count_(pop_count),
|
2011-01-03 16:57:46 +00:00
|
|
|
environment_length_(environment_length),
|
2010-12-07 11:31:57 +00:00
|
|
|
values_(2),
|
|
|
|
assigned_indexes_(2) {}
|
|
|
|
virtual ~HSimulate() {}
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
bool HasAstId() const { return ast_id_ != AstNode::kNoNumber; }
|
|
|
|
int ast_id() const { return ast_id_; }
|
|
|
|
void set_ast_id(int id) {
|
|
|
|
ASSERT(!HasAstId());
|
|
|
|
ast_id_ = id;
|
|
|
|
}
|
|
|
|
|
2011-01-03 16:57:46 +00:00
|
|
|
int environment_length() const { return environment_length_; }
|
2010-12-07 11:31:57 +00:00
|
|
|
int pop_count() const { return pop_count_; }
|
|
|
|
const ZoneList<HValue*>* values() const { return &values_; }
|
|
|
|
int GetAssignedIndexAt(int index) const {
|
|
|
|
ASSERT(HasAssignedIndexAt(index));
|
|
|
|
return assigned_indexes_[index];
|
|
|
|
}
|
|
|
|
bool HasAssignedIndexAt(int index) const {
|
|
|
|
return assigned_indexes_[index] != kNoIndex;
|
|
|
|
}
|
|
|
|
void AddAssignedValue(int index, HValue* value) {
|
|
|
|
AddValue(index, value);
|
|
|
|
}
|
|
|
|
void AddPushedValue(HValue* value) {
|
|
|
|
AddValue(kNoIndex, value);
|
|
|
|
}
|
|
|
|
virtual int OperandCount() const { return values_.length(); }
|
|
|
|
virtual HValue* OperandAt(int index) const { return values_[index]; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Simulate, "simulate")
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void InternalSetOperandAt(int index, HValue* value) {
|
|
|
|
values_[index] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static const int kNoIndex = -1;
|
|
|
|
void AddValue(int index, HValue* value) {
|
|
|
|
assigned_indexes_.Add(index);
|
|
|
|
// Resize the list of pushed values.
|
|
|
|
values_.Add(NULL);
|
|
|
|
// Set the operand through the base method in HValue to make sure that the
|
|
|
|
// use lists are correctly updated.
|
|
|
|
SetOperandAt(values_.length() - 1, value);
|
|
|
|
}
|
|
|
|
int ast_id_;
|
|
|
|
int pop_count_;
|
2011-01-03 16:57:46 +00:00
|
|
|
int environment_length_;
|
2010-12-07 11:31:57 +00:00
|
|
|
ZoneList<HValue*> values_;
|
|
|
|
ZoneList<int> assigned_indexes_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HStackCheck: public HInstruction {
|
|
|
|
public:
|
|
|
|
HStackCheck() { }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Throw, "stack_check")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HEnterInlined: public HInstruction {
|
|
|
|
public:
|
|
|
|
HEnterInlined(Handle<JSFunction> closure, FunctionLiteral* function)
|
|
|
|
: closure_(closure), function_(function) {
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
Handle<JSFunction> closure() const { return closure_; }
|
|
|
|
FunctionLiteral* function() const { return function_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(EnterInlined, "enter_inlined")
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<JSFunction> closure_;
|
|
|
|
FunctionLiteral* function_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HLeaveInlined: public HInstruction {
|
|
|
|
public:
|
|
|
|
HLeaveInlined() {}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LeaveInlined, "leave_inlined")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HPushArgument: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HPushArgument(HValue* value)
|
|
|
|
: HUnaryOperation(value), argument_index_(-1) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
HValue* argument() const { return OperandAt(0); }
|
|
|
|
int argument_index() const { return argument_index_; }
|
|
|
|
void set_argument_index(int index) {
|
|
|
|
ASSERT(argument_index_ == -1 || index == argument_index_);
|
|
|
|
argument_index_ = index;
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push_argument")
|
|
|
|
|
|
|
|
private:
|
|
|
|
int argument_index_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HGlobalObject: public HInstruction {
|
|
|
|
public:
|
|
|
|
HGlobalObject() {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
SetFlag(kDependsOnCalls);
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global_object")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HGlobalReceiver: public HInstruction {
|
|
|
|
public:
|
|
|
|
HGlobalReceiver() {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
SetFlag(kDependsOnCalls);
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver, "global_receiver")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCall: public HInstruction {
|
|
|
|
public:
|
|
|
|
// Construct a call with uninitialized arguments. The argument count
|
|
|
|
// includes the receiver.
|
|
|
|
explicit HCall(int count);
|
|
|
|
|
|
|
|
virtual HType CalculateInferredType() const { return HType::Tagged(); }
|
|
|
|
|
|
|
|
// TODO(3190496): This needs a cleanup. We don't want the arguments
|
|
|
|
// be operands of the call instruction. This results in bad code quality.
|
|
|
|
virtual int argument_count() const { return arguments_.length(); }
|
|
|
|
virtual int OperandCount() const { return argument_count(); }
|
|
|
|
virtual HValue* OperandAt(int index) const { return arguments_[index]; }
|
|
|
|
virtual HPushArgument* PushArgumentAt(int index) const {
|
|
|
|
return HPushArgument::cast(OperandAt(index));
|
|
|
|
}
|
|
|
|
virtual HValue* ArgumentAt(int index) const {
|
|
|
|
return PushArgumentAt(index)->argument();
|
|
|
|
}
|
|
|
|
virtual void SetArgumentAt(int index, HPushArgument* push_argument);
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(Call)
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void InternalSetOperandAt(int index, HValue* value) {
|
|
|
|
arguments_[index] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int argument_count_;
|
|
|
|
Vector<HValue*> arguments_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCallConstantFunction: public HCall {
|
|
|
|
public:
|
|
|
|
HCallConstantFunction(Handle<JSFunction> function, int argument_count)
|
|
|
|
: HCall(argument_count), function_(function) { }
|
|
|
|
|
|
|
|
Handle<JSFunction> function() const { return function_; }
|
|
|
|
bool IsApplyFunction() const {
|
|
|
|
return function_->code() == Builtins::builtin(Builtins::FunctionApply);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction, "call_constant_function")
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<JSFunction> function_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCallKeyed: public HCall {
|
|
|
|
public:
|
|
|
|
HCallKeyed(HValue* key, int argument_count)
|
|
|
|
: HCall(argument_count + 1) {
|
|
|
|
SetOperandAt(0, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(3190496): This is a hack to get an additional operand that
|
|
|
|
// is not an argument to work with the current setup. This _needs_ a cleanup.
|
|
|
|
// (see HCall)
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
HValue* key() const { return OperandAt(0); }
|
|
|
|
virtual int argument_count() const { return arguments_.length() - 1; }
|
|
|
|
virtual int OperandCount() const { return arguments_.length(); }
|
|
|
|
virtual HValue* OperandAt(int index) const { return arguments_[index]; }
|
|
|
|
virtual HPushArgument* PushArgumentAt(int index) const {
|
|
|
|
return HPushArgument::cast(OperandAt(index + 1));
|
|
|
|
}
|
|
|
|
virtual void SetArgumentAt(int index, HPushArgument* push_argument) {
|
|
|
|
HCall::SetArgumentAt(index + 1, push_argument);
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call_keyed")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCallNamed: public HCall {
|
|
|
|
public:
|
|
|
|
HCallNamed(Handle<String> name, int argument_count)
|
|
|
|
: HCall(argument_count), name_(name) { }
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
Handle<String> name() const { return name_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call_named")
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<String> name_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCallFunction: public HCall {
|
|
|
|
public:
|
|
|
|
explicit HCallFunction(int argument_count) : HCall(argument_count) { }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call_function")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCallGlobal: public HCall {
|
|
|
|
public:
|
|
|
|
HCallGlobal(Handle<String> name, int argument_count)
|
|
|
|
: HCall(argument_count), name_(name) { }
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
Handle<String> name() const { return name_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call_global")
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<String> name_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCallKnownGlobal: public HCall {
|
|
|
|
public:
|
|
|
|
HCallKnownGlobal(Handle<JSFunction> target,
|
|
|
|
int argument_count)
|
|
|
|
: HCall(argument_count), target_(target) { }
|
|
|
|
|
|
|
|
Handle<JSFunction> target() const { return target_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal, "call_known_global")
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<JSFunction> target_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCallNew: public HCall {
|
|
|
|
public:
|
|
|
|
explicit HCallNew(int argument_count) : HCall(argument_count) { }
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
HValue* constructor() const { return ArgumentAt(0); }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call_new")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCallRuntime: public HCall {
|
|
|
|
public:
|
|
|
|
HCallRuntime(Handle<String> name,
|
|
|
|
Runtime::Function* c_function,
|
|
|
|
int argument_count)
|
|
|
|
: HCall(argument_count), c_function_(c_function), name_(name) { }
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
Runtime::Function* function() const { return c_function_; }
|
|
|
|
Handle<String> name() const { return name_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call_runtime")
|
|
|
|
|
|
|
|
private:
|
|
|
|
Runtime::Function* c_function_;
|
|
|
|
Handle<String> name_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-12-30 19:30:42 +00:00
|
|
|
class HJSArrayLength: public HUnaryOperation {
|
2010-12-07 11:31:57 +00:00
|
|
|
public:
|
2010-12-30 19:30:42 +00:00
|
|
|
explicit HJSArrayLength(HValue* value) : HUnaryOperation(value) {
|
2010-12-07 11:31:57 +00:00
|
|
|
// The length of an array is stored as a tagged value in the array
|
|
|
|
// object. It is guaranteed to be 32 bit integer, but it can be
|
|
|
|
// represented as either a smi or heap number.
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kDependsOnArrayLengths);
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
2010-12-30 19:30:42 +00:00
|
|
|
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js_array_length")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HFixedArrayLength: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HFixedArrayLength(HValue* value) : HUnaryOperation(value) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kDependsOnArrayLengths);
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed_array_length")
|
2010-12-07 11:31:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HBitNot: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HBitNot(HValue* value) : HUnaryOperation(value) {
|
|
|
|
set_representation(Representation::Integer32());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
SetFlag(kTruncatingToInt32);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Integer32();
|
|
|
|
}
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(BitNot, "bit_not")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HUnaryMathOperation: public HUnaryOperation {
|
|
|
|
public:
|
2010-12-14 18:53:48 +00:00
|
|
|
HUnaryMathOperation(HValue* value, BuiltinFunctionId op)
|
2010-12-07 11:31:57 +00:00
|
|
|
: HUnaryOperation(value), op_(op) {
|
|
|
|
switch (op) {
|
|
|
|
case kMathFloor:
|
|
|
|
case kMathRound:
|
|
|
|
case kMathCeil:
|
|
|
|
set_representation(Representation::Integer32());
|
|
|
|
break;
|
|
|
|
case kMathAbs:
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kFlexibleRepresentation);
|
|
|
|
break;
|
|
|
|
case kMathSqrt:
|
2010-12-08 14:32:40 +00:00
|
|
|
case kMathPowHalf:
|
2010-12-14 13:21:29 +00:00
|
|
|
case kMathLog:
|
2010-12-20 13:52:14 +00:00
|
|
|
case kMathSin:
|
|
|
|
case kMathCos:
|
2010-12-07 11:31:57 +00:00
|
|
|
set_representation(Representation::Double());
|
2010-12-14 18:53:48 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
switch (op_) {
|
|
|
|
case kMathFloor:
|
|
|
|
case kMathRound:
|
|
|
|
case kMathCeil:
|
|
|
|
case kMathSqrt:
|
2010-12-08 14:32:40 +00:00
|
|
|
case kMathPowHalf:
|
2010-12-14 13:21:29 +00:00
|
|
|
case kMathLog:
|
2010-12-20 13:52:14 +00:00
|
|
|
case kMathSin:
|
|
|
|
case kMathCos:
|
2010-12-07 11:31:57 +00:00
|
|
|
return Representation::Double();
|
|
|
|
break;
|
|
|
|
case kMathAbs:
|
|
|
|
return representation();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return Representation::None();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HValue* Canonicalize() {
|
|
|
|
// If the input is integer32 then we replace the floor instruction
|
|
|
|
// with its inputs. This happens before the representation changes are
|
|
|
|
// introduced.
|
|
|
|
if (op() == kMathFloor) {
|
|
|
|
if (value()->representation().IsInteger32()) return value();
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2010-12-14 18:53:48 +00:00
|
|
|
BuiltinFunctionId op() const { return op_; }
|
2010-12-07 11:31:57 +00:00
|
|
|
const char* OpName() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary_math_operation")
|
|
|
|
|
2010-12-16 15:40:02 +00:00
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
|
|
|
|
return op_ == b->op();
|
|
|
|
}
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
private:
|
2010-12-14 18:53:48 +00:00
|
|
|
BuiltinFunctionId op_;
|
2010-12-07 11:31:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HLoadElements: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HLoadElements(HValue* value) : HUnaryOperation(value) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
SetFlag(kDependsOnMaps);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCheckMap: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
HCheckMap(HValue* value, Handle<Map> map)
|
|
|
|
: HUnaryOperation(value), map_(map) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
SetFlag(kDependsOnMaps);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Handle<Map> map() const { return map_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check_map")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HCheckMap* b = HCheckMap::cast(other);
|
|
|
|
return map_.is_identical_to(b->map());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<Map> map_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCheckFunction: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
HCheckFunction(HValue* value, Handle<JSFunction> function)
|
|
|
|
: HUnaryOperation(value), target_(function) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Handle<JSFunction> target() const { return target_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check_function")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HCheckFunction* b = HCheckFunction::cast(other);
|
|
|
|
return target_.is_identical_to(b->target());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<JSFunction> target_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCheckInstanceType: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
// Check that the instance type is in the range [first, last] where
|
|
|
|
// both first and last are included.
|
|
|
|
HCheckInstanceType(HValue* value, InstanceType first, InstanceType last)
|
|
|
|
: HUnaryOperation(value), first_(first), last_(last) {
|
|
|
|
ASSERT(first <= last);
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static HCheckInstanceType* NewIsJSObjectOrJSFunction(HValue* value);
|
|
|
|
|
|
|
|
InstanceType first() const { return first_; }
|
|
|
|
InstanceType last() const { return last_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check_instance_type")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
// TODO(ager): It could be nice to allow the ommision of instance
|
|
|
|
// type checks if we have already performed an instance type check
|
|
|
|
// with a larger range.
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HCheckInstanceType* b = HCheckInstanceType::cast(other);
|
|
|
|
return (first_ == b->first()) && (last_ == b->last());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
InstanceType first_;
|
|
|
|
InstanceType last_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCheckNonSmi: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HCheckNonSmi(HValue* value) : HUnaryOperation(value) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check_non_smi")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCheckPrototypeMaps: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
HCheckPrototypeMaps(HValue* value,
|
|
|
|
Handle<JSObject> holder,
|
|
|
|
Handle<Map> receiver_map)
|
|
|
|
: HUnaryOperation(value),
|
|
|
|
holder_(holder),
|
|
|
|
receiver_map_(receiver_map) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
SetFlag(kDependsOnMaps);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Handle<JSObject> holder() const { return holder_; }
|
|
|
|
Handle<Map> receiver_map() const { return receiver_map_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check_prototype_maps")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other);
|
|
|
|
return holder_.is_identical_to(b->holder()) &&
|
|
|
|
receiver_map_.is_identical_to(b->receiver_map());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<JSObject> holder_;
|
|
|
|
Handle<Map> receiver_map_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCheckSmi: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HCheckSmi(HValue* value) : HUnaryOperation(value) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check_smi")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HPhi: public HValue {
|
|
|
|
public:
|
|
|
|
explicit HPhi(int merged_index)
|
|
|
|
: inputs_(2),
|
|
|
|
merged_index_(merged_index),
|
|
|
|
phi_id_(-1) {
|
|
|
|
for (int i = 0; i < Representation::kNumRepresentations; i++) {
|
|
|
|
non_phi_uses_[i] = 0;
|
|
|
|
indirect_uses_[i] = 0;
|
|
|
|
}
|
|
|
|
ASSERT(merged_index >= 0);
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kFlexibleRepresentation);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation InferredRepresentation() const {
|
|
|
|
bool double_occurred = false;
|
|
|
|
bool int32_occurred = false;
|
|
|
|
for (int i = 0; i < OperandCount(); ++i) {
|
|
|
|
HValue* value = OperandAt(i);
|
|
|
|
if (value->representation().IsDouble()) double_occurred = true;
|
|
|
|
if (value->representation().IsInteger32()) int32_occurred = true;
|
|
|
|
if (value->representation().IsTagged()) return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (double_occurred) return Representation::Double();
|
|
|
|
if (int32_occurred) return Representation::Integer32();
|
|
|
|
return Representation::None();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Range* InferRange();
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return representation();
|
|
|
|
}
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
virtual int OperandCount() const { return inputs_.length(); }
|
|
|
|
virtual HValue* OperandAt(int index) const { return inputs_[index]; }
|
|
|
|
HValue* GetRedundantReplacement() const;
|
|
|
|
void AddInput(HValue* value);
|
|
|
|
|
|
|
|
bool HasReceiverOperand();
|
|
|
|
|
|
|
|
int merged_index() const { return merged_index_; }
|
|
|
|
|
|
|
|
virtual const char* Mnemonic() const { return "phi"; }
|
|
|
|
|
|
|
|
virtual void PrintTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(Phi)
|
|
|
|
|
|
|
|
void InitRealUses(int id);
|
|
|
|
void AddNonPhiUsesFrom(HPhi* other);
|
|
|
|
void AddIndirectUsesTo(int* use_count);
|
|
|
|
|
|
|
|
int tagged_non_phi_uses() const {
|
|
|
|
return non_phi_uses_[Representation::kTagged];
|
|
|
|
}
|
|
|
|
int int32_non_phi_uses() const {
|
|
|
|
return non_phi_uses_[Representation::kInteger32];
|
|
|
|
}
|
|
|
|
int double_non_phi_uses() const {
|
|
|
|
return non_phi_uses_[Representation::kDouble];
|
|
|
|
}
|
|
|
|
int tagged_indirect_uses() const {
|
|
|
|
return indirect_uses_[Representation::kTagged];
|
|
|
|
}
|
|
|
|
int int32_indirect_uses() const {
|
|
|
|
return indirect_uses_[Representation::kInteger32];
|
|
|
|
}
|
|
|
|
int double_indirect_uses() const {
|
|
|
|
return indirect_uses_[Representation::kDouble];
|
|
|
|
}
|
|
|
|
int phi_id() { return phi_id_; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void DeleteFromGraph();
|
|
|
|
virtual void InternalSetOperandAt(int index, HValue* value) {
|
|
|
|
inputs_[index] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
ZoneList<HValue*> inputs_;
|
|
|
|
int merged_index_;
|
|
|
|
|
|
|
|
int non_phi_uses_[Representation::kNumRepresentations];
|
|
|
|
int indirect_uses_[Representation::kNumRepresentations];
|
|
|
|
int phi_id_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HArgumentsObject: public HInstruction {
|
|
|
|
public:
|
|
|
|
HArgumentsObject() {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kIsArguments);
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject, "arguments-object")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HConstant: public HInstruction {
|
|
|
|
public:
|
|
|
|
HConstant(Handle<Object> handle, Representation r);
|
|
|
|
|
|
|
|
Handle<Object> handle() const { return handle_; }
|
|
|
|
|
2010-12-25 14:14:16 +00:00
|
|
|
bool InOldSpace() const { return !Heap::InNewSpace(*handle_); }
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
virtual bool EmitAtUses() const { return !representation().IsDouble(); }
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
bool IsInteger() const { return handle_->IsSmi(); }
|
|
|
|
HConstant* CopyToRepresentation(Representation r) const;
|
|
|
|
HConstant* CopyToTruncatedInt32() const;
|
|
|
|
bool HasInteger32Value() const { return has_int32_value_; }
|
|
|
|
int32_t Integer32Value() const {
|
|
|
|
ASSERT(HasInteger32Value());
|
|
|
|
return int32_value_;
|
|
|
|
}
|
|
|
|
bool HasDoubleValue() const { return has_double_value_; }
|
|
|
|
double DoubleValue() const {
|
|
|
|
ASSERT(HasDoubleValue());
|
|
|
|
return double_value_;
|
|
|
|
}
|
|
|
|
bool HasStringValue() const { return handle_->IsString(); }
|
|
|
|
|
|
|
|
virtual intptr_t Hashcode() const {
|
|
|
|
ASSERT(!Heap::allow_allocation(false));
|
|
|
|
return reinterpret_cast<intptr_t>(*handle());
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const { }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Constant, "constant")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual Range* InferRange();
|
|
|
|
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HConstant* other_constant = HConstant::cast(other);
|
|
|
|
return handle().is_identical_to(other_constant->handle());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<Object> handle_;
|
|
|
|
HType constant_type_;
|
|
|
|
|
|
|
|
// The following two values represent the int32 and the double value of the
|
|
|
|
// given constant if there is a lossless conversion between the constant
|
|
|
|
// and the specific representation.
|
|
|
|
bool has_int32_value_;
|
|
|
|
int32_t int32_value_;
|
|
|
|
bool has_double_value_;
|
|
|
|
double double_value_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HBinaryOperation: public HInstruction {
|
|
|
|
public:
|
|
|
|
HBinaryOperation(HValue* left, HValue* right) {
|
|
|
|
ASSERT(left != NULL && right != NULL);
|
|
|
|
SetOperandAt(0, left);
|
|
|
|
SetOperandAt(1, right);
|
|
|
|
}
|
|
|
|
|
|
|
|
HValue* left() const { return OperandAt(0); }
|
|
|
|
HValue* right() const { return OperandAt(1); }
|
|
|
|
|
|
|
|
// TODO(kasperl): Move these helpers to the IA-32 Lithium
|
|
|
|
// instruction sequence builder.
|
|
|
|
HValue* LeastConstantOperand() const {
|
|
|
|
if (IsCommutative() && left()->IsConstant()) return right();
|
|
|
|
return left();
|
|
|
|
}
|
|
|
|
HValue* MostConstantOperand() const {
|
|
|
|
if (IsCommutative() && left()->IsConstant()) return left();
|
|
|
|
return right();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool IsCommutative() const { return false; }
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
virtual int OperandCount() const { return operands_.length(); }
|
|
|
|
virtual HValue* OperandAt(int index) const { return operands_[index]; }
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(BinaryOperation)
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void InternalSetOperandAt(int index, HValue* value) {
|
|
|
|
operands_[index] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
HOperandVector<2> operands_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HApplyArguments: public HInstruction {
|
|
|
|
public:
|
|
|
|
HApplyArguments(HValue* function,
|
|
|
|
HValue* receiver,
|
|
|
|
HValue* length,
|
|
|
|
HValue* elements) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetOperandAt(0, function);
|
|
|
|
SetOperandAt(1, receiver);
|
|
|
|
SetOperandAt(2, length);
|
|
|
|
SetOperandAt(3, elements);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
// The length is untagged, all other inputs are tagged.
|
|
|
|
return (index == 2)
|
|
|
|
? Representation::Integer32()
|
|
|
|
: Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
HValue* function() const { return OperandAt(0); }
|
|
|
|
HValue* receiver() const { return OperandAt(1); }
|
|
|
|
HValue* length() const { return OperandAt(2); }
|
|
|
|
HValue* elements() const { return OperandAt(3); }
|
|
|
|
|
|
|
|
virtual int OperandCount() const { return operands_.length(); }
|
|
|
|
virtual HValue* OperandAt(int index) const { return operands_[index]; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply_arguments")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void InternalSetOperandAt(int index, HValue* value) {
|
|
|
|
operands_[index] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
HOperandVector<4> operands_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HArgumentsElements: public HInstruction {
|
|
|
|
public:
|
|
|
|
HArgumentsElements() {
|
|
|
|
// The value produced by this instruction is a pointer into the stack
|
|
|
|
// that looks as if it was a smi because of alignment.
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments_elements")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HArgumentsLength: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
|
|
|
|
set_representation(Representation::Integer32());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments_length")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HAccessArgumentsAt: public HInstruction {
|
|
|
|
public:
|
|
|
|
HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
SetOperandAt(0, arguments);
|
|
|
|
SetOperandAt(1, length);
|
|
|
|
SetOperandAt(2, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
// The arguments elements is considered tagged.
|
|
|
|
return index == 0
|
|
|
|
? Representation::Tagged()
|
|
|
|
: Representation::Integer32();
|
|
|
|
}
|
|
|
|
|
|
|
|
HValue* arguments() const { return operands_[0]; }
|
|
|
|
HValue* length() const { return operands_[1]; }
|
|
|
|
HValue* index() const { return operands_[2]; }
|
|
|
|
|
|
|
|
virtual int OperandCount() const { return operands_.length(); }
|
|
|
|
virtual HValue* OperandAt(int index) const { return operands_[index]; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access_arguments_at")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void InternalSetOperandAt(int index, HValue* value) {
|
|
|
|
operands_[index] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
HOperandVector<3> operands_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HBoundsCheck: public HBinaryOperation {
|
|
|
|
public:
|
|
|
|
HBoundsCheck(HValue* index, HValue* length)
|
|
|
|
: HBinaryOperation(index, length) {
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Integer32();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
virtual void Verify() const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
HValue* index() const { return left(); }
|
|
|
|
HValue* length() const { return right(); }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds_check")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HBitwiseBinaryOperation: public HBinaryOperation {
|
|
|
|
public:
|
|
|
|
HBitwiseBinaryOperation(HValue* left, HValue* right)
|
|
|
|
: HBinaryOperation(left, right) {
|
|
|
|
// Default to truncating, Integer32, UseGVN.
|
|
|
|
set_representation(Representation::Integer32());
|
|
|
|
SetFlag(kTruncatingToInt32);
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Integer32();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(BitwiseBinaryOperation)
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HArithmeticBinaryOperation: public HBinaryOperation {
|
|
|
|
public:
|
|
|
|
HArithmeticBinaryOperation(HValue* left, HValue* right)
|
|
|
|
: HBinaryOperation(left, right) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kFlexibleRepresentation);
|
|
|
|
SetFlagMask(AllSideEffects());
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void RepresentationChanged(Representation to) {
|
|
|
|
if (!to.IsTagged()) {
|
|
|
|
ClearFlagMask(AllSideEffects());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return representation();
|
|
|
|
}
|
|
|
|
virtual Representation InferredRepresentation() const {
|
|
|
|
if (left()->representation().Equals(right()->representation())) {
|
|
|
|
return left()->representation();
|
|
|
|
}
|
|
|
|
return HValue::InferredRepresentation();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(ArithmeticBinaryOperation)
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCompare: public HBinaryOperation {
|
|
|
|
public:
|
|
|
|
HCompare(HValue* left, HValue* right, Token::Value token)
|
|
|
|
: HBinaryOperation(left, right), token_(token) {
|
|
|
|
ASSERT(Token::IsCompareOp(token));
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlagMask(AllSideEffects());
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetInputRepresentation(Representation r);
|
|
|
|
virtual bool EmitAtUses() const { return uses()->length() <= 1; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return input_representation_;
|
|
|
|
}
|
|
|
|
Representation GetInputRepresentation() const {
|
|
|
|
return input_representation_;
|
|
|
|
}
|
|
|
|
Token::Value token() const { return token_; }
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
virtual intptr_t Hashcode() const {
|
|
|
|
return HValue::Hashcode() * 7 + token_;
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Compare, "compare")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HCompare* comp = HCompare::cast(other);
|
|
|
|
return token_ == comp->token();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Representation input_representation_;
|
|
|
|
Token::Value token_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCompareJSObjectEq: public HBinaryOperation {
|
|
|
|
public:
|
|
|
|
HCompareJSObjectEq(HValue* left, HValue* right)
|
|
|
|
: HBinaryOperation(left, right) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool EmitAtUses() const { return uses()->length() <= 1; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CompareJSObjectEq, "compare-js-object-eq")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HUnaryPredicate: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HUnaryPredicate(HValue* value) : HUnaryOperation(value) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
virtual bool EmitAtUses() const { return uses()->length() <= 1; }
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HIsNull: public HUnaryPredicate {
|
|
|
|
public:
|
|
|
|
HIsNull(HValue* value, bool is_strict)
|
|
|
|
: HUnaryPredicate(value), is_strict_(is_strict) { }
|
|
|
|
|
|
|
|
bool is_strict() const { return is_strict_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(IsNull, "is_null")
|
|
|
|
|
2010-12-16 15:40:02 +00:00
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HIsNull* b = HIsNull::cast(other);
|
|
|
|
return is_strict_ == b->is_strict();
|
|
|
|
}
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
private:
|
|
|
|
bool is_strict_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-12-15 12:32:19 +00:00
|
|
|
class HIsObject: public HUnaryPredicate {
|
|
|
|
public:
|
|
|
|
explicit HIsObject(HValue* value) : HUnaryPredicate(value) { }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(IsObject, "is_object")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
class HIsSmi: public HUnaryPredicate {
|
|
|
|
public:
|
|
|
|
explicit HIsSmi(HValue* value) : HUnaryPredicate(value) { }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(IsSmi, "is_smi")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HHasInstanceType: public HUnaryPredicate {
|
|
|
|
public:
|
|
|
|
HHasInstanceType(HValue* value, InstanceType type)
|
|
|
|
: HUnaryPredicate(value), from_(type), to_(type) { }
|
|
|
|
HHasInstanceType(HValue* value, InstanceType from, InstanceType to)
|
|
|
|
: HUnaryPredicate(value), from_(from), to_(to) {
|
|
|
|
ASSERT(to == LAST_TYPE); // Others not implemented yet in backend.
|
|
|
|
}
|
|
|
|
|
|
|
|
InstanceType from() { return from_; }
|
|
|
|
InstanceType to() { return to_; }
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(HasInstanceType, "has_instance_type")
|
|
|
|
|
2010-12-16 15:40:02 +00:00
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HHasInstanceType* b = HHasInstanceType::cast(other);
|
|
|
|
return (from_ == b->from()) && (to_ == b->to());
|
|
|
|
}
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
private:
|
|
|
|
InstanceType from_;
|
|
|
|
InstanceType to_; // Inclusive range, not all combinations work.
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HHasCachedArrayIndex: public HUnaryPredicate {
|
|
|
|
public:
|
|
|
|
explicit HHasCachedArrayIndex(HValue* value) : HUnaryPredicate(value) { }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex, "has_cached_array_index")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HClassOfTest: public HUnaryPredicate {
|
|
|
|
public:
|
|
|
|
HClassOfTest(HValue* value, Handle<String> class_name)
|
|
|
|
: HUnaryPredicate(value), class_name_(class_name) { }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class_of_test")
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
Handle<String> class_name() const { return class_name_; }
|
|
|
|
|
2010-12-16 15:40:02 +00:00
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HClassOfTest* b = HClassOfTest::cast(other);
|
|
|
|
return class_name_.is_identical_to(b->class_name_);
|
|
|
|
}
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
private:
|
|
|
|
Handle<String> class_name_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HTypeofIs: public HUnaryPredicate {
|
|
|
|
public:
|
|
|
|
HTypeofIs(HValue* value, Handle<String> type_literal)
|
|
|
|
: HUnaryPredicate(value), type_literal_(type_literal) { }
|
|
|
|
|
|
|
|
Handle<String> type_literal() { return type_literal_; }
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(TypeofIs, "typeof_is")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HTypeofIs* b = HTypeofIs::cast(other);
|
|
|
|
return type_literal_.is_identical_to(b->type_literal_);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<String> type_literal_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HInstanceOf: public HBinaryOperation {
|
|
|
|
public:
|
|
|
|
HInstanceOf(HValue* left, HValue* right) : HBinaryOperation(left, right) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlagMask(AllSideEffects());
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool EmitAtUses() const { return uses()->length() <= 1; }
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance_of")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-01-05 11:17:37 +00:00
|
|
|
class HInstanceOfKnownGlobal: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
HInstanceOfKnownGlobal(HValue* left, Handle<JSFunction> right)
|
|
|
|
: HUnaryOperation(left), function_(right) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlagMask(AllSideEffects());
|
|
|
|
}
|
|
|
|
|
|
|
|
Handle<JSFunction> function() { return function_; }
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal,
|
|
|
|
"instance_of_known_global")
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<JSFunction> function_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-12-08 14:32:40 +00:00
|
|
|
class HPower: public HBinaryOperation {
|
|
|
|
public:
|
|
|
|
HPower(HValue* left, HValue* right)
|
|
|
|
: HBinaryOperation(left, right) {
|
|
|
|
set_representation(Representation::Double());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return (index == 1) ? Representation::None() : Representation::Double();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Power, "power")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
class HAdd: public HArithmeticBinaryOperation {
|
|
|
|
public:
|
|
|
|
HAdd(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
|
|
|
|
SetFlag(kCanOverflow);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add is only commutative if two integer values are added and not if two
|
|
|
|
// tagged values are added (because it might be a String concatenation).
|
|
|
|
virtual bool IsCommutative() const {
|
|
|
|
return !representation().IsTagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Add, "add")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual Range* InferRange();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HSub: public HArithmeticBinaryOperation {
|
|
|
|
public:
|
|
|
|
HSub(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
|
|
|
|
SetFlag(kCanOverflow);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Sub, "sub")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual Range* InferRange();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HMul: public HArithmeticBinaryOperation {
|
|
|
|
public:
|
|
|
|
HMul(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
|
|
|
|
SetFlag(kCanOverflow);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
|
|
|
|
// Only commutative if it is certain that not two objects are multiplicated.
|
|
|
|
virtual bool IsCommutative() const {
|
|
|
|
return !representation().IsTagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Mul, "mul")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual Range* InferRange();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HMod: public HArithmeticBinaryOperation {
|
|
|
|
public:
|
|
|
|
HMod(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
|
|
|
|
SetFlag(kCanBeDivByZero);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Mod, "mod")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual Range* InferRange();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HDiv: public HArithmeticBinaryOperation {
|
|
|
|
public:
|
|
|
|
HDiv(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
|
|
|
|
SetFlag(kCanBeDivByZero);
|
|
|
|
SetFlag(kCanOverflow);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Div, "div")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual Range* InferRange();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HBitAnd: public HBitwiseBinaryOperation {
|
|
|
|
public:
|
|
|
|
HBitAnd(HValue* left, HValue* right)
|
|
|
|
: HBitwiseBinaryOperation(left, right) { }
|
|
|
|
|
|
|
|
virtual bool IsCommutative() const { return true; }
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(BitAnd, "bit_and")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual Range* InferRange();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HBitXor: public HBitwiseBinaryOperation {
|
|
|
|
public:
|
|
|
|
HBitXor(HValue* left, HValue* right)
|
|
|
|
: HBitwiseBinaryOperation(left, right) { }
|
|
|
|
|
|
|
|
virtual bool IsCommutative() const { return true; }
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(BitXor, "bit_xor")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HBitOr: public HBitwiseBinaryOperation {
|
|
|
|
public:
|
|
|
|
HBitOr(HValue* left, HValue* right)
|
|
|
|
: HBitwiseBinaryOperation(left, right) { }
|
|
|
|
|
|
|
|
virtual bool IsCommutative() const { return true; }
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(BitOr, "bit_or")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual Range* InferRange();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HShl: public HBitwiseBinaryOperation {
|
|
|
|
public:
|
|
|
|
HShl(HValue* left, HValue* right)
|
|
|
|
: HBitwiseBinaryOperation(left, right) { }
|
|
|
|
|
|
|
|
virtual Range* InferRange();
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Shl, "shl")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HShr: public HBitwiseBinaryOperation {
|
|
|
|
public:
|
|
|
|
HShr(HValue* left, HValue* right)
|
|
|
|
: HBitwiseBinaryOperation(left, right) { }
|
|
|
|
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Shr, "shr")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HSar: public HBitwiseBinaryOperation {
|
|
|
|
public:
|
|
|
|
HSar(HValue* left, HValue* right)
|
|
|
|
: HBitwiseBinaryOperation(left, right) { }
|
|
|
|
|
|
|
|
virtual Range* InferRange();
|
|
|
|
virtual HType CalculateInferredType() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Sar, "sar")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HOsrEntry: public HInstruction {
|
|
|
|
public:
|
|
|
|
explicit HOsrEntry(int ast_id) : ast_id_(ast_id) {
|
|
|
|
SetFlag(kChangesOsrEntries);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ast_id() const { return ast_id_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr_entry")
|
|
|
|
|
|
|
|
private:
|
|
|
|
int ast_id_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HParameter: public HInstruction {
|
|
|
|
public:
|
|
|
|
explicit HParameter(unsigned index) : index_(index) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned index() const { return index_; }
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
|
|
|
|
|
|
|
|
private:
|
|
|
|
unsigned index_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HCallStub: public HInstruction {
|
|
|
|
public:
|
|
|
|
HCallStub(CodeStub::Major major_key, int argument_count)
|
|
|
|
: major_key_(major_key),
|
|
|
|
argument_count_(argument_count),
|
|
|
|
transcendental_type_(TranscendentalCache::kNumberOfCaches) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlagMask(AllSideEffects());
|
|
|
|
}
|
|
|
|
|
|
|
|
CodeStub::Major major_key() { return major_key_; }
|
|
|
|
int argument_count() { return argument_count_; }
|
|
|
|
|
|
|
|
void set_transcendental_type(TranscendentalCache::Type transcendental_type) {
|
|
|
|
transcendental_type_ = transcendental_type;
|
|
|
|
}
|
|
|
|
TranscendentalCache::Type transcendental_type() {
|
|
|
|
return transcendental_type_;
|
|
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(CallStub, "call_stub")
|
|
|
|
|
|
|
|
private:
|
|
|
|
CodeStub::Major major_key_;
|
|
|
|
int argument_count_;
|
|
|
|
TranscendentalCache::Type transcendental_type_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HUnknownOSRValue: public HInstruction {
|
|
|
|
public:
|
|
|
|
HUnknownOSRValue() { set_representation(Representation::Tagged()); }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown_osr_value")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HLoadGlobal: public HInstruction {
|
|
|
|
public:
|
|
|
|
HLoadGlobal(Handle<JSGlobalPropertyCell> cell, bool check_hole_value)
|
|
|
|
: cell_(cell), check_hole_value_(check_hole_value) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
SetFlag(kDependsOnGlobalVars);
|
|
|
|
}
|
|
|
|
|
|
|
|
Handle<JSGlobalPropertyCell> cell() const { return cell_; }
|
|
|
|
bool check_hole_value() const { return check_hole_value_; }
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
virtual intptr_t Hashcode() const {
|
|
|
|
ASSERT(!Heap::allow_allocation(false));
|
|
|
|
return reinterpret_cast<intptr_t>(*cell_);
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadGlobal, "load_global")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HLoadGlobal* b = HLoadGlobal::cast(other);
|
|
|
|
return cell_.is_identical_to(b->cell());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<JSGlobalPropertyCell> cell_;
|
|
|
|
bool check_hole_value_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HStoreGlobal: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
HStoreGlobal(HValue* value, Handle<JSGlobalPropertyCell> cell)
|
|
|
|
: HUnaryOperation(value), cell_(cell) {
|
|
|
|
SetFlag(kChangesGlobalVars);
|
|
|
|
}
|
|
|
|
|
|
|
|
Handle<JSGlobalPropertyCell> cell() const { return cell_; }
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreGlobal, "store_global")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HStoreGlobal* b = HStoreGlobal::cast(other);
|
|
|
|
return cell_.is_identical_to(b->cell());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<JSGlobalPropertyCell> cell_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HLoadNamedField: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
HLoadNamedField(HValue* object, bool is_in_object, int offset)
|
|
|
|
: HUnaryOperation(object),
|
|
|
|
is_in_object_(is_in_object),
|
|
|
|
offset_(offset) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
if (is_in_object) {
|
|
|
|
SetFlag(kDependsOnInobjectFields);
|
|
|
|
} else {
|
|
|
|
SetFlag(kDependsOnBackingStoreFields);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
HValue* object() const { return OperandAt(0); }
|
|
|
|
bool is_in_object() const { return is_in_object_; }
|
|
|
|
int offset() const { return offset_; }
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load_named_field")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HLoadNamedField* b = HLoadNamedField::cast(other);
|
|
|
|
return is_in_object_ == b->is_in_object_ && offset_ == b->offset_;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool is_in_object_;
|
|
|
|
int offset_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HLoadNamedGeneric: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
HLoadNamedGeneric(HValue* object, Handle<Object> name)
|
|
|
|
: HUnaryOperation(object), name_(name) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlagMask(AllSideEffects());
|
|
|
|
}
|
|
|
|
|
|
|
|
HValue* object() const { return OperandAt(0); }
|
|
|
|
Handle<Object> name() const { return name_; }
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load_named_generic")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HLoadNamedGeneric* b = HLoadNamedGeneric::cast(other);
|
|
|
|
return name_.is_identical_to(b->name_);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<Object> name_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-12-22 15:43:32 +00:00
|
|
|
class HLoadFunctionPrototype: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HLoadFunctionPrototype(HValue* function)
|
|
|
|
: HUnaryOperation(function) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlagMask(kDependsOnFunctionPrototypes);
|
|
|
|
}
|
|
|
|
|
|
|
|
HValue* function() const { return OperandAt(0); }
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load_function_prototype")
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const { return true; }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
class HLoadKeyed: public HBinaryOperation {
|
|
|
|
public:
|
|
|
|
HLoadKeyed(HValue* obj, HValue* key) : HBinaryOperation(obj, key) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
HValue* object() const { return OperandAt(0); }
|
|
|
|
HValue* key() const { return OperandAt(1); }
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(LoadKeyed)
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HLoadKeyedFastElement: public HLoadKeyed {
|
|
|
|
public:
|
|
|
|
HLoadKeyedFastElement(HValue* obj, HValue* key) : HLoadKeyed(obj, key) {
|
|
|
|
SetFlag(kDependsOnArrayElements);
|
|
|
|
SetFlag(kUseGVN);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
// The key is supposed to be Integer32.
|
|
|
|
return (index == 1) ? Representation::Integer32()
|
|
|
|
: Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement,
|
|
|
|
"load_keyed_fast_element")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HLoadKeyedGeneric: public HLoadKeyed {
|
|
|
|
public:
|
|
|
|
HLoadKeyedGeneric(HValue* obj, HValue* key) : HLoadKeyed(obj, key) {
|
|
|
|
SetFlagMask(AllSideEffects());
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load_keyed_generic")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-12-25 14:14:16 +00:00
|
|
|
static inline bool StoringValueNeedsWriteBarrier(HValue* value) {
|
|
|
|
return !value->type().IsSmi() &&
|
|
|
|
!(value->IsConstant() && HConstant::cast(value)->InOldSpace());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
class HStoreNamed: public HBinaryOperation {
|
|
|
|
public:
|
|
|
|
HStoreNamed(HValue* obj, Handle<Object> name, HValue* val)
|
|
|
|
: HBinaryOperation(obj, val), name_(name) {
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
HValue* object() const { return OperandAt(0); }
|
|
|
|
Handle<Object> name() const { return name_; }
|
|
|
|
HValue* value() const { return OperandAt(1); }
|
|
|
|
void set_value(HValue* value) { SetOperandAt(1, value); }
|
|
|
|
|
2010-12-25 14:14:16 +00:00
|
|
|
bool NeedsWriteBarrier() const {
|
|
|
|
return StoringValueNeedsWriteBarrier(value());
|
|
|
|
}
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
DECLARE_INSTRUCTION(StoreNamed)
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool DataEquals(HValue* other) const {
|
|
|
|
HStoreNamed* b = HStoreNamed::cast(other);
|
|
|
|
return name_.is_identical_to(b->name_);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<Object> name_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HStoreNamedField: public HStoreNamed {
|
|
|
|
public:
|
|
|
|
HStoreNamedField(HValue* obj,
|
|
|
|
Handle<Object> name,
|
|
|
|
HValue* val,
|
|
|
|
bool in_object,
|
|
|
|
int offset)
|
|
|
|
: HStoreNamed(obj, name, val),
|
|
|
|
is_in_object_(in_object),
|
|
|
|
offset_(offset) {
|
|
|
|
if (is_in_object_) {
|
|
|
|
SetFlag(kChangesInobjectFields);
|
|
|
|
} else {
|
|
|
|
SetFlag(kChangesBackingStoreFields);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store_named_field")
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
|
|
|
|
bool is_in_object() const { return is_in_object_; }
|
|
|
|
int offset() const { return offset_; }
|
|
|
|
Handle<Map> transition() const { return transition_; }
|
|
|
|
void set_transition(Handle<Map> map) { transition_ = map; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool is_in_object_;
|
|
|
|
int offset_;
|
|
|
|
Handle<Map> transition_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HStoreNamedGeneric: public HStoreNamed {
|
|
|
|
public:
|
|
|
|
HStoreNamedGeneric(HValue* obj, Handle<Object> name, HValue* val)
|
|
|
|
: HStoreNamed(obj, name, val) {
|
|
|
|
SetFlagMask(AllSideEffects());
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store_named_generic")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HStoreKeyed: public HInstruction {
|
|
|
|
public:
|
|
|
|
HStoreKeyed(HValue* obj, HValue* key, HValue* val) {
|
|
|
|
SetOperandAt(0, obj);
|
|
|
|
SetOperandAt(1, key);
|
|
|
|
SetOperandAt(2, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void PrintDataTo(StringStream* stream) const;
|
|
|
|
virtual int OperandCount() const { return operands_.length(); }
|
|
|
|
virtual HValue* OperandAt(int index) const { return operands_[index]; }
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
HValue* object() const { return OperandAt(0); }
|
|
|
|
HValue* key() const { return OperandAt(1); }
|
|
|
|
HValue* value() const { return OperandAt(2); }
|
|
|
|
|
2010-12-25 14:14:16 +00:00
|
|
|
bool NeedsWriteBarrier() const {
|
|
|
|
return StoringValueNeedsWriteBarrier(value());
|
|
|
|
}
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
DECLARE_INSTRUCTION(StoreKeyed)
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void InternalSetOperandAt(int index, HValue* value) {
|
|
|
|
operands_[index] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
HOperandVector<3> operands_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HStoreKeyedFastElement: public HStoreKeyed {
|
|
|
|
public:
|
|
|
|
HStoreKeyedFastElement(HValue* obj, HValue* key, HValue* val)
|
|
|
|
: HStoreKeyed(obj, key, val) {
|
|
|
|
SetFlag(kChangesArrayElements);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
// The key is supposed to be Integer32.
|
|
|
|
return (index == 1) ? Representation::Integer32()
|
|
|
|
: Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement,
|
|
|
|
"store_keyed_fast_element")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HStoreKeyedGeneric: public HStoreKeyed {
|
|
|
|
public:
|
|
|
|
HStoreKeyedGeneric(HValue* obj, HValue* key, HValue* val)
|
|
|
|
: HStoreKeyed(obj, key, val) {
|
|
|
|
SetFlagMask(AllSideEffects());
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store_keyed_generic")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HMaterializedLiteral: public HInstruction {
|
|
|
|
public:
|
|
|
|
HMaterializedLiteral(int index, int depth)
|
|
|
|
: literal_index_(index), depth_(depth) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
}
|
|
|
|
|
|
|
|
int literal_index() const { return literal_index_; }
|
|
|
|
int depth() const { return depth_; }
|
|
|
|
|
|
|
|
DECLARE_INSTRUCTION(MaterializedLiteral)
|
|
|
|
|
|
|
|
private:
|
|
|
|
int literal_index_;
|
|
|
|
int depth_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HArrayLiteral: public HMaterializedLiteral {
|
|
|
|
public:
|
|
|
|
HArrayLiteral(Handle<FixedArray> constant_elements,
|
|
|
|
int length,
|
|
|
|
int literal_index,
|
|
|
|
int depth)
|
|
|
|
: HMaterializedLiteral(literal_index, depth),
|
|
|
|
length_(length),
|
|
|
|
constant_elements_(constant_elements) {}
|
|
|
|
|
|
|
|
Handle<FixedArray> constant_elements() const { return constant_elements_; }
|
|
|
|
int length() const { return length_; }
|
|
|
|
|
|
|
|
bool IsCopyOnWrite() const;
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array_literal")
|
|
|
|
|
|
|
|
private:
|
|
|
|
int length_;
|
|
|
|
Handle<FixedArray> constant_elements_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HObjectLiteral: public HMaterializedLiteral {
|
|
|
|
public:
|
|
|
|
HObjectLiteral(Handle<FixedArray> constant_properties,
|
|
|
|
bool fast_elements,
|
|
|
|
int literal_index,
|
|
|
|
int depth)
|
|
|
|
: HMaterializedLiteral(literal_index, depth),
|
|
|
|
constant_properties_(constant_properties),
|
|
|
|
fast_elements_(fast_elements) {}
|
|
|
|
|
|
|
|
Handle<FixedArray> constant_properties() const {
|
|
|
|
return constant_properties_;
|
|
|
|
}
|
|
|
|
bool fast_elements() const { return fast_elements_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object_literal")
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<FixedArray> constant_properties_;
|
|
|
|
bool fast_elements_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HRegExpLiteral: public HMaterializedLiteral {
|
|
|
|
public:
|
|
|
|
HRegExpLiteral(Handle<String> pattern,
|
|
|
|
Handle<String> flags,
|
|
|
|
int literal_index)
|
|
|
|
: HMaterializedLiteral(literal_index, 0),
|
|
|
|
pattern_(pattern),
|
|
|
|
flags_(flags) { }
|
|
|
|
|
|
|
|
Handle<String> pattern() { return pattern_; }
|
|
|
|
Handle<String> flags() { return flags_; }
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp_literal")
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<String> pattern_;
|
|
|
|
Handle<String> flags_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HFunctionLiteral: public HInstruction {
|
|
|
|
public:
|
|
|
|
HFunctionLiteral(Handle<SharedFunctionInfo> shared, bool pretenure)
|
|
|
|
: shared_info_(shared), pretenure_(pretenure) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function_literal")
|
|
|
|
|
|
|
|
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
|
|
|
|
bool pretenure() const { return pretenure_; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<SharedFunctionInfo> shared_info_;
|
|
|
|
bool pretenure_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HTypeof: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HTypeof(HValue* value) : HUnaryOperation(value) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HValueOf: public HUnaryOperation {
|
|
|
|
public:
|
|
|
|
explicit HValueOf(HValue* value) : HUnaryOperation(value) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value_of")
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class HDeleteProperty: public HBinaryOperation {
|
|
|
|
public:
|
|
|
|
HDeleteProperty(HValue* obj, HValue* key)
|
|
|
|
: HBinaryOperation(obj, key) {
|
|
|
|
set_representation(Representation::Tagged());
|
|
|
|
SetFlagMask(AllSideEffects());
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Representation RequiredInputRepresentation(int index) const {
|
|
|
|
return Representation::Tagged();
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete_property")
|
|
|
|
|
|
|
|
HValue* object() const { return left(); }
|
|
|
|
HValue* key() const { return right(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
#undef DECLARE_INSTRUCTION
|
|
|
|
#undef DECLARE_CONCRETE_INSTRUCTION
|
|
|
|
|
|
|
|
} } // namespace v8::internal
|
|
|
|
|
|
|
|
#endif // V8_HYDROGEN_INSTRUCTIONS_H_
|