summaryrefslogtreecommitdiff
path: root/deps/v8/src/hydrogen-instructions.h
diff options
context:
space:
mode:
authorTrevor Norris <trev.norris@gmail.com>2013-03-18 13:49:34 -0700
committerBen Noordhuis <info@bnoordhuis.nl>2013-03-20 01:11:01 +0100
commit83261e789eb903da39f279cb5a161611482e7df5 (patch)
tree4133b5ca9f53bed4365e1a94544a227d68a0cf12 /deps/v8/src/hydrogen-instructions.h
parenta05f973f82d2be8527aad4c371d40d3c7e4c564e (diff)
downloadnode-83261e789eb903da39f279cb5a161611482e7df5.tar.gz
deps: update v8 to 3.17.13
Diffstat (limited to 'deps/v8/src/hydrogen-instructions.h')
-rw-r--r--deps/v8/src/hydrogen-instructions.h2233
1 files changed, 1639 insertions, 594 deletions
diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h
index 015212dd7..f741f292e 100644
--- a/deps/v8/src/hydrogen-instructions.h
+++ b/deps/v8/src/hydrogen-instructions.h
@@ -45,6 +45,7 @@ namespace internal {
// Forward declarations.
class HBasicBlock;
class HEnvironment;
+class HInferRepresentation;
class HInstruction;
class HLoopInformation;
class HValue;
@@ -63,6 +64,7 @@ class LChunkBuilder;
V(AbnormalExit) \
V(AccessArgumentsAt) \
V(Add) \
+ V(Allocate) \
V(AllocateObject) \
V(ApplyArguments) \
V(ArgumentsElements) \
@@ -73,6 +75,7 @@ class LChunkBuilder;
V(BitNot) \
V(BlockEntry) \
V(BoundsCheck) \
+ V(BoundsCheckBaseIndexInformation) \
V(Branch) \
V(CallConstantFunction) \
V(CallFunction) \
@@ -81,6 +84,7 @@ class LChunkBuilder;
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
+ V(CallNewArray) \
V(CallRuntime) \
V(CallStub) \
V(Change) \
@@ -90,6 +94,7 @@ class LChunkBuilder;
V(CheckNonSmi) \
V(CheckPrototypeMaps) \
V(CheckSmi) \
+ V(CheckSmiOrInt32) \
V(ClampToUint8) \
V(ClassOfTestAndBranch) \
V(CompareIDAndBranch) \
@@ -103,6 +108,7 @@ class LChunkBuilder;
V(DeleteProperty) \
V(Deoptimize) \
V(Div) \
+ V(DummyUse) \
V(ElementsKind) \
V(EnterInlined) \
V(FastLiteral) \
@@ -115,9 +121,12 @@ class LChunkBuilder;
V(Goto) \
V(HasCachedArrayIndexAndBranch) \
V(HasInstanceTypeAndBranch) \
+ V(InductionVariableAnnotation) \
V(In) \
+ V(InnerAllocatedObject) \
V(InstanceOf) \
V(InstanceOfKnownGlobal) \
+ V(InstanceSize) \
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
V(IsNilAndBranch) \
@@ -133,10 +142,8 @@ class LChunkBuilder;
V(LoadFunctionPrototype) \
V(LoadGlobalCell) \
V(LoadGlobalGeneric) \
- V(LoadKeyedFastDoubleElement) \
- V(LoadKeyedFastElement) \
+ V(LoadKeyed) \
V(LoadKeyedGeneric) \
- V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
@@ -145,6 +152,7 @@ class LChunkBuilder;
V(MathMinMax) \
V(Mod) \
V(Mul) \
+ V(NumericConstraint) \
V(ObjectLiteral) \
V(OsrEntry) \
V(OuterContext) \
@@ -154,7 +162,9 @@ class LChunkBuilder;
V(Random) \
V(RegExpLiteral) \
V(Return) \
+ V(Ror) \
V(Sar) \
+ V(SeqStringSetChar) \
V(Shl) \
V(Shr) \
V(Simulate) \
@@ -163,10 +173,8 @@ class LChunkBuilder;
V(StoreContextSlot) \
V(StoreGlobalCell) \
V(StoreGlobalGeneric) \
- V(StoreKeyedFastDoubleElement) \
- V(StoreKeyedFastElement) \
+ V(StoreKeyed) \
V(StoreKeyedGeneric) \
- V(StoreKeyedSpecializedArrayElement) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(StringAdd) \
@@ -179,6 +187,7 @@ class LChunkBuilder;
V(Throw) \
V(ToFastProperties) \
V(TransitionElementsKind) \
+ V(TrapAllocationMemento) \
V(Typeof) \
V(TypeofIsAndBranch) \
V(UnaryMathOperation) \
@@ -193,6 +202,7 @@ class LChunkBuilder;
V(WrapReceiver)
#define GVN_TRACKED_FLAG_LIST(V) \
+ V(Maps) \
V(NewSpacePromotion)
#define GVN_UNTRACKED_FLAG_LIST(V) \
@@ -205,7 +215,6 @@ class LChunkBuilder;
V(DoubleArrayElements) \
V(SpecializedArrayElements) \
V(GlobalVars) \
- V(Maps) \
V(ArrayLengths) \
V(ContextSlots) \
V(OsrEntries)
@@ -228,11 +237,9 @@ class LChunkBuilder;
#ifdef DEBUG
-#define ASSERT_ALLOCATION_DISABLED do { \
- OptimizingCompilerThread* thread = \
- ISOLATE->optimizing_compiler_thread(); \
- ASSERT(thread->IsOptimizerThread() || !HEAP->IsAllocationAllowed()); \
- } while (0)
+#define ASSERT_ALLOCATION_DISABLED \
+ ASSERT(isolate()->optimizing_compiler_thread()->IsOptimizerThread() || \
+ !isolate()->heap()->IsAllocationAllowed())
#else
#define ASSERT_ALLOCATION_DISABLED do {} while (0)
#endif
@@ -311,9 +318,9 @@ class Representation {
public:
enum Kind {
kNone,
- kTagged,
- kDouble,
kInteger32,
+ kDouble,
+ kTagged,
kExternal,
kNumRepresentations
};
@@ -326,10 +333,18 @@ class Representation {
static Representation Double() { return Representation(kDouble); }
static Representation External() { return Representation(kExternal); }
+ static Representation FromKind(Kind kind) { return Representation(kind); }
+
bool Equals(const Representation& other) {
return kind_ == other.kind_;
}
+ bool is_more_general_than(const Representation& other) {
+ ASSERT(kind_ != kExternal);
+ ASSERT(other.kind_ != kExternal);
+ return kind_ > other.kind_;
+ }
+
Kind kind() const { return static_cast<Kind>(kind_); }
bool IsNone() const { return kind_ == kNone; }
bool IsTagged() const { return kind_ == kTagged; }
@@ -372,7 +387,7 @@ class HType {
return HType(static_cast<Type>(type_ & other.type_));
}
- bool Equals(const HType& other) {
+ bool Equals(const HType& other) const {
return type_ == other.type_;
}
@@ -380,61 +395,61 @@ class HType {
return Combine(other).Equals(other);
}
- bool IsTagged() {
+ bool IsTagged() const {
ASSERT(type_ != kUninitialized);
return ((type_ & kTagged) == kTagged);
}
- bool IsTaggedPrimitive() {
+ bool IsTaggedPrimitive() const {
ASSERT(type_ != kUninitialized);
return ((type_ & kTaggedPrimitive) == kTaggedPrimitive);
}
- bool IsTaggedNumber() {
+ bool IsTaggedNumber() const {
ASSERT(type_ != kUninitialized);
return ((type_ & kTaggedNumber) == kTaggedNumber);
}
- bool IsSmi() {
+ bool IsSmi() const {
ASSERT(type_ != kUninitialized);
return ((type_ & kSmi) == kSmi);
}
- bool IsHeapNumber() {
+ bool IsHeapNumber() const {
ASSERT(type_ != kUninitialized);
return ((type_ & kHeapNumber) == kHeapNumber);
}
- bool IsString() {
+ bool IsString() const {
ASSERT(type_ != kUninitialized);
return ((type_ & kString) == kString);
}
- bool IsBoolean() {
+ bool IsBoolean() const {
ASSERT(type_ != kUninitialized);
return ((type_ & kBoolean) == kBoolean);
}
- bool IsNonPrimitive() {
+ bool IsNonPrimitive() const {
ASSERT(type_ != kUninitialized);
return ((type_ & kNonPrimitive) == kNonPrimitive);
}
- bool IsJSArray() {
+ bool IsJSArray() const {
ASSERT(type_ != kUninitialized);
return ((type_ & kJSArray) == kJSArray);
}
- bool IsJSObject() {
+ bool IsJSObject() const {
ASSERT(type_ != kUninitialized);
return ((type_ & kJSObject) == kJSObject);
}
- bool IsUninitialized() {
+ bool IsUninitialized() const {
return type_ == kUninitialized;
}
- bool IsHeapObject() {
+ bool IsHeapObject() const {
ASSERT(type_ != kUninitialized);
return IsHeapNumber() || IsString() || IsNonPrimitive();
}
@@ -539,6 +554,244 @@ enum GVNFlag {
#undef COUNT_FLAG
};
+
+class NumericRelation {
+ public:
+ enum Kind { NONE, EQ, GT, GE, LT, LE, NE };
+ static const char* MnemonicFromKind(Kind kind) {
+ switch (kind) {
+ case NONE: return "NONE";
+ case EQ: return "EQ";
+ case GT: return "GT";
+ case GE: return "GE";
+ case LT: return "LT";
+ case LE: return "LE";
+ case NE: return "NE";
+ }
+ UNREACHABLE();
+ return NULL;
+ }
+ const char* Mnemonic() const { return MnemonicFromKind(kind_); }
+
+ static NumericRelation None() { return NumericRelation(NONE); }
+ static NumericRelation Eq() { return NumericRelation(EQ); }
+ static NumericRelation Gt() { return NumericRelation(GT); }
+ static NumericRelation Ge() { return NumericRelation(GE); }
+ static NumericRelation Lt() { return NumericRelation(LT); }
+ static NumericRelation Le() { return NumericRelation(LE); }
+ static NumericRelation Ne() { return NumericRelation(NE); }
+
+ bool IsNone() { return kind_ == NONE; }
+
+ static NumericRelation FromToken(Token::Value token) {
+ switch (token) {
+ case Token::EQ: return Eq();
+ case Token::EQ_STRICT: return Eq();
+ case Token::LT: return Lt();
+ case Token::GT: return Gt();
+ case Token::LTE: return Le();
+ case Token::GTE: return Ge();
+ case Token::NE: return Ne();
+ case Token::NE_STRICT: return Ne();
+ default: return None();
+ }
+ }
+
+ // The semantics of "Reversed" is that if "x rel y" is true then also
+ // "y rel.Reversed() x" is true, and that rel.Reversed().Reversed() == rel.
+ NumericRelation Reversed() {
+ switch (kind_) {
+ case NONE: return None();
+ case EQ: return Eq();
+ case GT: return Lt();
+ case GE: return Le();
+ case LT: return Gt();
+ case LE: return Ge();
+ case NE: return Ne();
+ }
+ UNREACHABLE();
+ return None();
+ }
+
+ // The semantics of "Negated" is that if "x rel y" is true then also
+ // "!(x rel.Negated() y)" is true.
+ NumericRelation Negated() {
+ switch (kind_) {
+ case NONE: return None();
+ case EQ: return Ne();
+ case GT: return Le();
+ case GE: return Lt();
+ case LT: return Ge();
+ case LE: return Gt();
+ case NE: return Eq();
+ }
+ UNREACHABLE();
+ return None();
+ }
+
+ // The semantics of "Implies" is that if "x rel y" is true
+ // then also "x other_relation y" is true.
+ bool Implies(NumericRelation other_relation) {
+ switch (kind_) {
+ case NONE: return false;
+ case EQ: return (other_relation.kind_ == EQ)
+ || (other_relation.kind_ == GE)
+ || (other_relation.kind_ == LE);
+ case GT: return (other_relation.kind_ == GT)
+ || (other_relation.kind_ == GE)
+ || (other_relation.kind_ == NE);
+ case LT: return (other_relation.kind_ == LT)
+ || (other_relation.kind_ == LE)
+ || (other_relation.kind_ == NE);
+ case GE: return (other_relation.kind_ == GE);
+ case LE: return (other_relation.kind_ == LE);
+ case NE: return (other_relation.kind_ == NE);
+ }
+ UNREACHABLE();
+ return false;
+ }
+
+ // The semantics of "IsExtendable" is that if
+ // "rel.IsExtendable(direction)" is true then
+ // "x rel y" implies "(x + direction) rel y" .
+ bool IsExtendable(int direction) {
+ switch (kind_) {
+ case NONE: return false;
+ case EQ: return false;
+ case GT: return (direction >= 0);
+ case GE: return (direction >= 0);
+ case LT: return (direction <= 0);
+ case LE: return (direction <= 0);
+ case NE: return false;
+ }
+ UNREACHABLE();
+ return false;
+ }
+
+ // CompoundImplies returns true when
+ // "((x + my_offset) >> my_scale) rel y" implies
+ // "((x + other_offset) >> other_scale) other_relation y".
+ bool CompoundImplies(NumericRelation other_relation,
+ int my_offset,
+ int my_scale,
+ int other_offset = 0,
+ int other_scale = 0) {
+ return Implies(other_relation) && ComponentsImply(
+ my_offset, my_scale, other_offset, other_scale);
+ }
+
+ private:
+ // ComponentsImply returns true when
+ // "((x + my_offset) >> my_scale) rel y" implies
+ // "((x + other_offset) >> other_scale) rel y".
+ bool ComponentsImply(int my_offset,
+ int my_scale,
+ int other_offset,
+ int other_scale) {
+ switch (kind_) {
+ case NONE: break; // Fall through to UNREACHABLE().
+ case EQ:
+ case NE: return my_offset == other_offset && my_scale == other_scale;
+ case GT:
+ case GE: return my_offset <= other_offset && my_scale >= other_scale;
+ case LT:
+ case LE: return my_offset >= other_offset && my_scale <= other_scale;
+ }
+ UNREACHABLE();
+ return false;
+ }
+
+ explicit NumericRelation(Kind kind) : kind_(kind) {}
+
+ Kind kind_;
+};
+
+
+class DecompositionResult BASE_EMBEDDED {
+ public:
+ DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
+
+ HValue* base() { return base_; }
+ int offset() { return offset_; }
+ int scale() { return scale_; }
+
+ bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
+ if (base_ == NULL) {
+ base_ = other_base;
+ offset_ = other_offset;
+ scale_ = other_scale;
+ return true;
+ } else {
+ if (scale_ == 0) {
+ base_ = other_base;
+ offset_ += other_offset;
+ scale_ = other_scale;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
+ swap(&base_, other_base);
+ swap(&offset_, other_offset);
+ swap(&scale_, other_scale);
+ }
+
+ private:
+ template <class T> void swap(T* a, T* b) {
+ T c(*a);
+ *a = *b;
+ *b = c;
+ }
+
+ HValue* base_;
+ int offset_;
+ int scale_;
+};
+
+
+class RangeEvaluationContext BASE_EMBEDDED {
+ public:
+ RangeEvaluationContext(HValue* value, HValue* upper);
+
+ HValue* lower_bound() { return lower_bound_; }
+ HValue* lower_bound_guarantee() { return lower_bound_guarantee_; }
+ HValue* candidate() { return candidate_; }
+ HValue* upper_bound() { return upper_bound_; }
+ HValue* upper_bound_guarantee() { return upper_bound_guarantee_; }
+ int offset() { return offset_; }
+ int scale() { return scale_; }
+
+ bool is_range_satisfied() {
+ return lower_bound_guarantee() != NULL && upper_bound_guarantee() != NULL;
+ }
+
+ void set_lower_bound_guarantee(HValue* guarantee) {
+ lower_bound_guarantee_ = ConvertGuarantee(guarantee);
+ }
+ void set_upper_bound_guarantee(HValue* guarantee) {
+ upper_bound_guarantee_ = ConvertGuarantee(guarantee);
+ }
+
+ void swap_candidate(DecompositionResult* other_candicate) {
+ other_candicate->SwapValues(&candidate_, &offset_, &scale_);
+ }
+
+ private:
+ HValue* ConvertGuarantee(HValue* guarantee);
+
+ HValue* lower_bound_;
+ HValue* lower_bound_guarantee_;
+ HValue* candidate_;
+ HValue* upper_bound_;
+ HValue* upper_bound_guarantee_;
+ int offset_;
+ int scale_;
+};
+
+
typedef EnumSet<GVNFlag> GVNFlagSet;
@@ -571,7 +824,13 @@ class HValue: public ZoneObject {
// HGraph::ComputeSafeUint32Operations is responsible for setting this
// flag.
kUint32,
- kLastFlag = kUint32
+ // If a phi is involved in the evaluation of a numeric constraint the
+ // recursion can cause an endless cycle: we use this flag to exit the loop.
+ kNumericConstraintEvaluationInProgress,
+ // This flag is set to true after the SetupInformativeDefinitions() pass
+ // has processed this instruction.
+ kIDefsProcessingDone,
+ kLastFlag = kIDefsProcessingDone
};
STATIC_ASSERT(kLastFlag < kBitsPerInt);
@@ -624,6 +883,9 @@ class HValue: public ZoneObject {
void SetBlock(HBasicBlock* block);
int LoopWeight() const;
+ // Note: Never call this method for an unlinked value.
+ Isolate* isolate() const;
+
int id() const { return id_; }
void set_id(int id) { id_ = id; }
@@ -632,13 +894,15 @@ class HValue: public ZoneObject {
virtual bool EmitAtUses() { return false; }
Representation representation() const { return representation_; }
void ChangeRepresentation(Representation r) {
- // Representation was already set and is allowed to be changed.
- ASSERT(!r.IsNone());
ASSERT(CheckFlag(kFlexibleRepresentation));
RepresentationChanged(r);
representation_ = r;
+ if (r.IsTagged()) {
+ // Tagged is the bottom of the lattice, don't go any further.
+ ClearFlag(kFlexibleRepresentation);
+ }
}
- void AssumeRepresentation(Representation r);
+ virtual void AssumeRepresentation(Representation r);
virtual bool IsConvertibleToInteger() const { return true; }
@@ -663,6 +927,48 @@ class HValue: public ZoneObject {
return NULL;
}
+ // There are HInstructions that do not really change a value, they
+ // only add pieces of information to it (like bounds checks, map checks,
+ // smi checks...).
+ // We call these instructions "informative definitions", or "iDef".
+ // One of the iDef operands is special because it is the value that is
+ // "transferred" to the output, we call it the "redefined operand".
+ // If an HValue is an iDef it must override RedefinedOperandIndex() so that
+ // it does not return kNoRedefinedOperand;
+ static const int kNoRedefinedOperand = -1;
+ virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
+ bool IsInformativeDefinition() {
+ return RedefinedOperandIndex() != kNoRedefinedOperand;
+ }
+ HValue* RedefinedOperand() {
+ return IsInformativeDefinition() ? OperandAt(RedefinedOperandIndex())
+ : NULL;
+ }
+
+ // A purely informative definition is an idef that will not emit code and
+ // should therefore be removed from the graph in the RestoreActualValues
+ // phase (so that live ranges will be shorter).
+ virtual bool IsPurelyInformativeDefinition() { return false; }
+
+ // This method must always return the original HValue SSA definition
+ // (regardless of any iDef of this value).
+ HValue* ActualValue() {
+ return IsInformativeDefinition() ? RedefinedOperand()->ActualValue()
+ : this;
+ }
+
+ virtual void AddInformativeDefinitions() {}
+
+ void UpdateRedefinedUsesWhileSettingUpInformativeDefinitions() {
+ UpdateRedefinedUsesInner<TestDominanceUsingProcessedFlag>();
+ }
+ void UpdateRedefinedUses() {
+ UpdateRedefinedUsesInner<Dominates>();
+ }
+
+ bool IsInteger32Constant();
+ int32_t GetInteger32Constant();
+
bool IsDefinedAfter(HBasicBlock* other) const;
// Operands.
@@ -736,16 +1042,11 @@ class HValue: public ZoneObject {
void ComputeInitialRange(Zone* zone);
// Representation helpers.
- virtual Representation RequiredInputRepresentation(int index) = 0;
-
- virtual Representation InferredRepresentation() {
- return representation();
- }
-
- // Type feedback access.
- virtual Representation ObservedInputRepresentation(int index) {
- return RequiredInputRepresentation(index);
+ virtual Representation observed_input_representation(int index) {
+ return Representation::None();
}
+ virtual Representation RequiredInputRepresentation(int index) = 0;
+ virtual void InferRepresentation(HInferRepresentation* h_infer);
// This gives the instruction an opportunity to replace itself with an
// instruction that does the same in some better way. To replace an
@@ -765,6 +1066,14 @@ class HValue: public ZoneObject {
const char* Mnemonic() const;
+ // Type information helpers.
+ bool HasMonomorphicJSObjectType();
+
+ // TODO(mstarzinger): For now instructions can override this function to
+ // specify statically known types, once HType can convey more information
+ // it should be based on the HType.
+ virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
+
// Updated the inferred type of this instruction and returns true if
// it has changed.
bool UpdateInferredType();
@@ -786,14 +1095,50 @@ class HValue: public ZoneObject {
virtual void Verify() = 0;
#endif
+ bool IsRelationTrue(NumericRelation relation,
+ HValue* other,
+ int offset = 0,
+ int scale = 0);
+
+ bool TryGuaranteeRange(HValue* upper_bound);
+ virtual bool TryDecompose(DecompositionResult* decomposition) {
+ if (RedefinedOperand() != NULL) {
+ return RedefinedOperand()->TryDecompose(decomposition);
+ } else {
+ return false;
+ }
+ }
+
protected:
+ void TryGuaranteeRangeRecursive(RangeEvaluationContext* context);
+
+ enum RangeGuaranteeDirection {
+ DIRECTION_NONE = 0,
+ DIRECTION_UPPER = 1,
+ DIRECTION_LOWER = 2,
+ DIRECTION_BOTH = DIRECTION_UPPER | DIRECTION_LOWER
+ };
+ virtual void SetResponsibilityForRange(RangeGuaranteeDirection direction) {}
+ virtual void TryGuaranteeRangeChanging(RangeEvaluationContext* context) {}
+
// This function must be overridden for instructions with flag kUseGVN, to
// compare the non-Operand parts of the instruction.
virtual bool DataEquals(HValue* other) {
UNREACHABLE();
return false;
}
+
+ virtual Representation RepresentationFromInputs() {
+ return representation();
+ }
+ Representation RepresentationFromUses();
+ virtual void UpdateRepresentation(Representation new_rep,
+ HInferRepresentation* h_infer,
+ const char* reason);
+ void AddDependantsToWorklist(HInferRepresentation* h_infer);
+
virtual void RepresentationChanged(Representation to) { }
+
virtual Range* InferRange(Zone* zone);
virtual void DeleteFromGraph() = 0;
virtual void InternalSetOperandAt(int index, HValue* value) = 0;
@@ -803,11 +1148,51 @@ class HValue: public ZoneObject {
}
void set_representation(Representation r) {
- // Representation is set-once.
ASSERT(representation_.IsNone() && !r.IsNone());
representation_ = r;
}
+ // Signature of a function testing if a HValue properly dominates another.
+ typedef bool (*DominanceTest)(HValue*, HValue*);
+
+ // Simple implementation of DominanceTest implemented walking the chain
+ // of Hinstructions (used in UpdateRedefinedUsesInner).
+ static bool Dominates(HValue* dominator, HValue* dominated);
+
+ // A fast implementation of DominanceTest that works only for the
+ // "current" instruction in the SetupInformativeDefinitions() phase.
+ // During that phase we use a flag to mark processed instructions, and by
+ // checking the flag we can quickly test if an instruction comes before or
+ // after the "current" one.
+ static bool TestDominanceUsingProcessedFlag(HValue* dominator,
+ HValue* dominated);
+
+ // If we are redefining an operand, update all its dominated uses (the
+ // function that checks if a use is dominated is the template argument).
+ template<DominanceTest TestDominance>
+ void UpdateRedefinedUsesInner() {
+ HValue* input = RedefinedOperand();
+ if (input != NULL) {
+ for (HUseIterator uses = input->uses(); !uses.Done(); uses.Advance()) {
+ HValue* use = uses.value();
+ if (TestDominance(this, use)) {
+ use->SetOperandAt(uses.index(), this);
+ }
+ }
+ }
+ }
+
+ // Informative definitions can override this method to state any numeric
+ // relation they provide on the redefined value.
+ // Returns true if it is guaranteed that:
+ // ((this + offset) >> scale) relation other
+ virtual bool IsRelationTrueInternal(NumericRelation relation,
+ HValue* other,
+ int offset = 0,
+ int scale = 0) {
+ return false;
+ }
+
static GVNFlagSet AllDependsOnFlagSet() {
GVNFlagSet result;
// Create changes mask.
@@ -1010,6 +1395,74 @@ class HBlockEntry: public HTemplateInstruction<0> {
};
+class HDummyUse: public HTemplateInstruction<1> {
+ public:
+ explicit HDummyUse(HValue* value) {
+ SetOperandAt(0, value);
+ // Pretend to be a Smi so that the HChange instructions inserted
+ // before any use generate as little code as possible.
+ set_representation(Representation::Tagged());
+ set_type(HType::Smi());
+ }
+
+ HValue* value() { return OperandAt(0); }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::None();
+ }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ DECLARE_CONCRETE_INSTRUCTION(DummyUse);
+};
+
+
+class HNumericConstraint : public HTemplateInstruction<2> {
+ public:
+ static HNumericConstraint* AddToGraph(HValue* constrained_value,
+ NumericRelation relation,
+ HValue* related_value,
+ HInstruction* insertion_point = NULL);
+
+ HValue* constrained_value() { return OperandAt(0); }
+ HValue* related_value() { return OperandAt(1); }
+ NumericRelation relation() { return relation_; }
+
+ virtual int RedefinedOperandIndex() { return 0; }
+ virtual bool IsPurelyInformativeDefinition() { return true; }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return representation();
+ }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ virtual bool IsRelationTrueInternal(NumericRelation other_relation,
+ HValue* other_related_value,
+ int offset = 0,
+ int scale = 0) {
+ if (related_value() == other_related_value) {
+ return relation().CompoundImplies(other_relation, offset, scale);
+ } else {
+ return false;
+ }
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(NumericConstraint)
+
+ private:
+ HNumericConstraint(HValue* constrained_value,
+ NumericRelation relation,
+ HValue* related_value)
+ : relation_(relation) {
+ SetOperandAt(0, constrained_value);
+ SetOperandAt(1, related_value);
+ }
+
+ NumericRelation relation_;
+};
+
+
// We insert soft-deoptimize when we hit code with unknown typefeedback,
// so that we get a chance of re-optimizing with useful typefeedback.
// HSoftDeoptimize does not end a basic block as opposed to HDeoptimize.
@@ -1116,6 +1569,7 @@ class HBranch: public HUnaryControlInstruction {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
}
+ virtual Representation observed_input_representation(int index);
ToBooleanStub::Types expected_input_types() const {
return expected_input_types_;
@@ -1156,10 +1610,12 @@ class HCompareMap: public HUnaryControlInstruction {
};
-class HReturn: public HTemplateControlInstruction<0, 1> {
+class HReturn: public HTemplateControlInstruction<0, 3> {
public:
- explicit HReturn(HValue* value) {
+ HReturn(HValue* value, HValue* context, HValue* parameter_count) {
SetOperandAt(0, value);
+ SetOperandAt(1, context);
+ SetOperandAt(2, parameter_count);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -1169,6 +1625,8 @@ class HReturn: public HTemplateControlInstruction<0, 1> {
virtual void PrintDataTo(StringStream* stream);
HValue* value() { return OperandAt(0); }
+ HValue* context() { return OperandAt(1); }
+ HValue* parameter_count() { return OperandAt(2); }
DECLARE_CONCRETE_INSTRUCTION(Return)
};
@@ -1245,6 +1703,8 @@ class HForceRepresentation: public HTemplateInstruction<1> {
return representation(); // Same as the output representation.
}
+ virtual void PrintDataTo(StringStream* stream);
+
DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)
};
@@ -1320,14 +1780,24 @@ class HClampToUint8: public HUnaryOperation {
};
+enum RemovableSimulate {
+ REMOVABLE_SIMULATE,
+ FIXED_SIMULATE
+};
+
+
class HSimulate: public HInstruction {
public:
- HSimulate(BailoutId ast_id, int pop_count, Zone* zone)
+ HSimulate(BailoutId ast_id,
+ int pop_count,
+ Zone* zone,
+ RemovableSimulate removable)
: ast_id_(ast_id),
pop_count_(pop_count),
values_(2, zone),
assigned_indexes_(2, zone),
- zone_(zone) {}
+ zone_(zone),
+ removable_(removable) {}
virtual ~HSimulate() {}
virtual void PrintDataTo(StringStream* stream);
@@ -1361,6 +1831,9 @@ class HSimulate: public HInstruction {
return Representation::None();
}
+ void MergeInto(HSimulate* other);
+ bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
+
DECLARE_CONCRETE_INSTRUCTION(Simulate)
#ifdef DEBUG
@@ -1387,6 +1860,7 @@ class HSimulate: public HInstruction {
ZoneList<HValue*> values_;
ZoneList<int> assigned_indexes_;
Zone* zone_;
+ RemovableSimulate removable_;
};
@@ -1412,7 +1886,7 @@ class HStackCheck: public HTemplateInstruction<1> {
// The stack check eliminator might try to eliminate the same stack
// check instruction multiple times.
if (IsLinked()) {
- DeleteFromGraph();
+ DeleteAndReplaceWith(NULL);
}
}
@@ -1440,18 +1914,18 @@ class HEnterInlined: public HTemplateInstruction<0> {
HEnterInlined(Handle<JSFunction> closure,
int arguments_count,
FunctionLiteral* function,
- CallKind call_kind,
InliningKind inlining_kind,
Variable* arguments_var,
- ZoneList<HValue*>* arguments_values)
+ ZoneList<HValue*>* arguments_values,
+ bool undefined_receiver)
: closure_(closure),
arguments_count_(arguments_count),
arguments_pushed_(false),
function_(function),
- call_kind_(call_kind),
inlining_kind_(inlining_kind),
arguments_var_(arguments_var),
- arguments_values_(arguments_values) {
+ arguments_values_(arguments_values),
+ undefined_receiver_(undefined_receiver) {
}
virtual void PrintDataTo(StringStream* stream);
@@ -1461,8 +1935,8 @@ class HEnterInlined: public HTemplateInstruction<0> {
bool arguments_pushed() const { return arguments_pushed_; }
void set_arguments_pushed() { arguments_pushed_ = true; }
FunctionLiteral* function() const { return function_; }
- CallKind call_kind() const { return call_kind_; }
InliningKind inlining_kind() const { return inlining_kind_; }
+ bool undefined_receiver() const { return undefined_receiver_; }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
@@ -1478,10 +1952,10 @@ class HEnterInlined: public HTemplateInstruction<0> {
int arguments_count_;
bool arguments_pushed_;
FunctionLiteral* function_;
- CallKind call_kind_;
InliningKind inlining_kind_;
Variable* arguments_var_;
ZoneList<HValue*>* arguments_values_;
+ bool undefined_receiver_;
};
@@ -1871,6 +2345,25 @@ class HCallNew: public HBinaryCall {
};
+class HCallNewArray: public HCallNew {
+ public:
+ HCallNewArray(HValue* context, HValue* constructor, int argument_count,
+ Handle<JSGlobalPropertyCell> type_cell)
+ : HCallNew(context, constructor, argument_count),
+ type_cell_(type_cell) {
+ }
+
+ Handle<JSGlobalPropertyCell> property_cell() const {
+ return type_cell_;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
+
+ private:
+ Handle<JSGlobalPropertyCell> type_cell_;
+};
+
+
class HCallRuntime: public HCall<1> {
public:
HCallRuntime(HValue* context,
@@ -1908,7 +2401,7 @@ class HJSArrayLength: public HTemplateInstruction<2> {
// object. It is guaranteed to be 32 bit integer, but it can be
// represented as either a smi or heap number.
SetOperandAt(0, value);
- SetOperandAt(1, typecheck);
+ SetOperandAt(1, typecheck != NULL ? typecheck : value);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnArrayLengths);
@@ -1922,7 +2415,11 @@ class HJSArrayLength: public HTemplateInstruction<2> {
virtual void PrintDataTo(StringStream* stream);
HValue* value() { return OperandAt(0); }
- HValue* typecheck() { return OperandAt(1); }
+ HValue* typecheck() {
+ ASSERT(HasTypeCheck());
+ return OperandAt(1);
+ }
+ bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); }
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength)
@@ -2013,6 +2510,9 @@ class HBitNot: public HUnaryOperation {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Integer32();
}
+ virtual Representation observed_input_representation(int index) {
+ return Representation::Integer32();
+ }
virtual HType CalculateInferredType();
virtual HValue* Canonicalize();
@@ -2029,35 +2529,10 @@ class HBitNot: public HUnaryOperation {
class HUnaryMathOperation: public HTemplateInstruction<2> {
public:
- HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
- : op_(op) {
- SetOperandAt(0, context);
- SetOperandAt(1, value);
- switch (op) {
- case kMathFloor:
- case kMathRound:
- case kMathCeil:
- set_representation(Representation::Integer32());
- break;
- case kMathAbs:
- set_representation(Representation::Tagged());
- SetFlag(kFlexibleRepresentation);
- SetGVNFlag(kChangesNewSpacePromotion);
- break;
- case kMathSqrt:
- case kMathPowHalf:
- case kMathLog:
- case kMathSin:
- case kMathCos:
- case kMathTan:
- set_representation(Representation::Double());
- SetGVNFlag(kChangesNewSpacePromotion);
- break;
- default:
- UNREACHABLE();
- }
- SetFlag(kUseGVN);
- }
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* value,
+ BuiltinFunctionId op);
HValue* context() { return OperandAt(0); }
HValue* value() { return OperandAt(1); }
@@ -2075,10 +2550,10 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
switch (op_) {
case kMathFloor:
case kMathRound:
- case kMathCeil:
case kMathSqrt:
case kMathPowHalf:
case kMathLog:
+ case kMathExp:
case kMathSin:
case kMathCos:
case kMathTan:
@@ -2106,6 +2581,39 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
}
private:
+ HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
+ : op_(op) {
+ SetOperandAt(0, context);
+ SetOperandAt(1, value);
+ switch (op) {
+ case kMathFloor:
+ case kMathRound:
+ case kMathCeil:
+ set_representation(Representation::Integer32());
+ break;
+ case kMathAbs:
+ // Not setting representation here: it is None intentionally.
+ SetFlag(kFlexibleRepresentation);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ break;
+ case kMathSqrt:
+ case kMathPowHalf:
+ case kMathLog:
+ case kMathSin:
+ case kMathCos:
+ case kMathTan:
+ set_representation(Representation::Double());
+ SetGVNFlag(kChangesNewSpacePromotion);
+ break;
+ case kMathExp:
+ set_representation(Representation::Double());
+ break;
+ default:
+ UNREACHABLE();
+ }
+ SetFlag(kUseGVN);
+ }
+
virtual bool IsDeletable() const { return true; }
BuiltinFunctionId op_;
@@ -2116,14 +2624,18 @@ class HLoadElements: public HTemplateInstruction<2> {
public:
HLoadElements(HValue* value, HValue* typecheck) {
SetOperandAt(0, value);
- SetOperandAt(1, typecheck);
+ SetOperandAt(1, typecheck != NULL ? typecheck : value);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnElementsPointer);
}
HValue* value() { return OperandAt(0); }
- HValue* typecheck() { return OperandAt(1); }
+ HValue* typecheck() {
+ ASSERT(HasTypeCheck());
+ return OperandAt(1);
+ }
+ bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); }
virtual void PrintDataTo(StringStream* stream);
@@ -2177,6 +2689,7 @@ class HCheckMaps: public HTemplateInstruction<2> {
SetOperandAt(1, typecheck != NULL ? typecheck : value);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
+ SetFlag(kTrackSideEffectDominators);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kDependsOnElementsKind);
map_set()->Add(map, zone);
@@ -2186,6 +2699,7 @@ class HCheckMaps: public HTemplateInstruction<2> {
SetOperandAt(1, value);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
+ SetFlag(kTrackSideEffectDominators);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kDependsOnElementsKind);
for (int i = 0; i < maps->length(); i++) {
@@ -2220,6 +2734,7 @@ class HCheckMaps: public HTemplateInstruction<2> {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+ virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator);
virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType();
@@ -2250,6 +2765,7 @@ class HCheckFunction: public HUnaryOperation {
: HUnaryOperation(value), target_(function) {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
+ target_in_new_space_ = Isolate::Current()->heap()->InNewSpace(*function);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -2263,6 +2779,7 @@ class HCheckFunction: public HUnaryOperation {
#endif
Handle<JSFunction> target() const { return target_; }
+ bool target_in_new_space() const { return target_in_new_space_; }
DECLARE_CONCRETE_INSTRUCTION(CheckFunction)
@@ -2274,6 +2791,7 @@ class HCheckFunction: public HUnaryOperation {
private:
Handle<JSFunction> target_;
+ bool target_in_new_space_;
};
@@ -2288,8 +2806,9 @@ class HCheckInstanceType: public HUnaryOperation {
static HCheckInstanceType* NewIsString(HValue* value, Zone* zone) {
return new(zone) HCheckInstanceType(value, IS_STRING);
}
- static HCheckInstanceType* NewIsSymbol(HValue* value, Zone* zone) {
- return new(zone) HCheckInstanceType(value, IS_SYMBOL);
+ static HCheckInstanceType* NewIsInternalizedString(
+ HValue* value, Zone* zone) {
+ return new(zone) HCheckInstanceType(value, IS_INTERNALIZED_STRING);
}
virtual void PrintDataTo(StringStream* stream);
@@ -2320,7 +2839,7 @@ class HCheckInstanceType: public HUnaryOperation {
IS_SPEC_OBJECT,
IS_JS_ARRAY,
IS_STRING,
- IS_SYMBOL,
+ IS_INTERNALIZED_STRING,
LAST_INTERVAL_CHECK = IS_JS_ARRAY
};
@@ -2374,18 +2893,24 @@ class HCheckNonSmi: public HUnaryOperation {
class HCheckPrototypeMaps: public HTemplateInstruction<0> {
public:
- HCheckPrototypeMaps(Handle<JSObject> prototype, Handle<JSObject> holder)
- : prototype_(prototype), holder_(holder) {
+ HCheckPrototypeMaps(Handle<JSObject> prototype,
+ Handle<JSObject> holder,
+ Zone* zone) : prototypes_(2, zone), maps_(2, zone) {
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
+ // Keep a list of all objects on the prototype chain up to the holder
+ // and the expected maps.
+ while (true) {
+ prototypes_.Add(prototype, zone);
+ maps_.Add(Handle<Map>(prototype->map()), zone);
+ if (prototype.is_identical_to(holder)) break;
+ prototype = Handle<JSObject>(JSObject::cast(prototype->GetPrototype()));
+ }
}
-#ifdef DEBUG
- virtual void Verify();
-#endif
+ ZoneList<Handle<JSObject> >* prototypes() { return &prototypes_; }
- Handle<JSObject> prototype() const { return prototype_; }
- Handle<JSObject> holder() const { return holder_; }
+ ZoneList<Handle<Map> >* maps() { return &maps_; }
DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps)
@@ -2397,21 +2922,45 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
virtual intptr_t Hashcode() {
ASSERT_ALLOCATION_DISABLED;
- intptr_t hash = reinterpret_cast<intptr_t>(*prototype());
- hash = 17 * hash + reinterpret_cast<intptr_t>(*holder());
+ // Dereferencing to use the object's raw address for hashing is safe.
+ HandleDereferenceGuard allow_handle_deref(isolate(),
+ HandleDereferenceGuard::ALLOW);
+ SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) ||
+ !isolate()->optimizing_compiler_thread()->IsOptimizerThread());
+ intptr_t hash = 0;
+ for (int i = 0; i < prototypes_.length(); i++) {
+ hash = 17 * hash + reinterpret_cast<intptr_t>(*prototypes_[i]);
+ hash = 17 * hash + reinterpret_cast<intptr_t>(*maps_[i]);
+ }
return hash;
}
+ bool CanOmitPrototypeChecks() {
+ for (int i = 0; i < maps()->length(); i++) {
+ if (!maps()->at(i)->CanOmitPrototypeChecks()) return false;
+ }
+ return true;
+ }
+
protected:
virtual bool DataEquals(HValue* other) {
HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other);
- return prototype_.is_identical_to(b->prototype()) &&
- holder_.is_identical_to(b->holder());
+#ifdef DEBUG
+ if (prototypes_.length() != b->prototypes()->length()) return false;
+ for (int i = 0; i < prototypes_.length(); i++) {
+ if (!prototypes_[i].is_identical_to(b->prototypes()->at(i))) return false;
+ if (!maps_[i].is_identical_to(b->maps()->at(i))) return false;
+ }
+ return true;
+#else
+ return prototypes_.first().is_identical_to(b->prototypes()->first()) &&
+ prototypes_.last().is_identical_to(b->prototypes()->last());
+#endif // DEBUG
}
private:
- Handle<JSObject> prototype_;
- Handle<JSObject> holder_;
+ ZoneList<Handle<JSObject> > prototypes_;
+ ZoneList<Handle<Map> > maps_;
};
@@ -2438,6 +2987,38 @@ class HCheckSmi: public HUnaryOperation {
};
+class HCheckSmiOrInt32: public HUnaryOperation {
+ public:
+ explicit HCheckSmiOrInt32(HValue* value) : HUnaryOperation(value) {
+ SetFlag(kFlexibleRepresentation);
+ SetFlag(kUseGVN);
+ }
+
+ virtual int RedefinedOperandIndex() { return 0; }
+ virtual Representation RequiredInputRepresentation(int index) {
+ return representation();
+ }
+ virtual void InferRepresentation(HInferRepresentation* h_infer);
+
+ virtual Representation observed_input_representation(int index) {
+ return Representation::Integer32();
+ }
+
+ virtual HValue* Canonicalize() {
+ if (representation().IsTagged() && !value()->type().IsSmi()) {
+ return this;
+ } else {
+ return value();
+ }
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(CheckSmiOrInt32)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+};
+
+
class HPhi: public HValue {
public:
HPhi(int merged_index, Zone* zone)
@@ -2451,13 +3032,15 @@ class HPhi: public HValue {
indirect_uses_[i] = 0;
}
ASSERT(merged_index >= 0);
- set_representation(Representation::Tagged());
SetFlag(kFlexibleRepresentation);
}
- virtual Representation InferredRepresentation();
+ virtual Representation RepresentationFromInputs();
virtual Range* InferRange(Zone* zone);
+ virtual void InferRepresentation(HInferRepresentation* h_infer);
+ Representation RepresentationObservedByAllNonPhiUses();
+ Representation RepresentationFromUseRequirements();
virtual Representation RequiredInputRepresentation(int index) {
return representation();
}
@@ -2472,6 +3055,8 @@ class HPhi: public HValue {
int merged_index() const { return merged_index_; }
+ virtual void AddInformativeDefinitions();
+
virtual void PrintTo(StringStream* stream);
#ifdef DEBUG
@@ -2521,20 +3106,28 @@ class HPhi: public HValue {
bool AllOperandsConvertibleToInteger() {
for (int i = 0; i < OperandCount(); ++i) {
if (!OperandAt(i)->IsConvertibleToInteger()) {
+ if (FLAG_trace_representation) {
+ HValue* input = OperandAt(i);
+ PrintF("#%d %s: Input #%d %s at %d is NCTI\n",
+ id(), Mnemonic(), input->id(), input->Mnemonic(), i);
+ }
return false;
}
}
return true;
}
- void ResetInteger32Uses();
-
protected:
virtual void DeleteFromGraph();
virtual void InternalSetOperandAt(int index, HValue* value) {
inputs_[index] = value;
}
+ virtual bool IsRelationTrueInternal(NumericRelation relation,
+ HValue* other,
+ int offset = 0,
+ int scale = 0);
+
private:
ZoneList<HValue*> inputs_;
int merged_index_;
@@ -2547,6 +3140,53 @@ class HPhi: public HValue {
};
+class HInductionVariableAnnotation : public HUnaryOperation {
+ public:
+ static HInductionVariableAnnotation* AddToGraph(HPhi* phi,
+ NumericRelation relation,
+ int operand_index);
+
+ NumericRelation relation() { return relation_; }
+ HValue* induction_base() { return phi_->OperandAt(operand_index_); }
+
+ virtual int RedefinedOperandIndex() { return 0; }
+ virtual bool IsPurelyInformativeDefinition() { return true; }
+ virtual Representation RequiredInputRepresentation(int index) {
+ return representation();
+ }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ virtual bool IsRelationTrueInternal(NumericRelation other_relation,
+ HValue* other_related_value,
+ int offset = 0,
+ int scale = 0) {
+ if (induction_base() == other_related_value) {
+ return relation().CompoundImplies(other_relation, offset, scale);
+ } else {
+ return false;
+ }
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(InductionVariableAnnotation)
+
+ private:
+ HInductionVariableAnnotation(HPhi* phi,
+ NumericRelation relation,
+ int operand_index)
+ : HUnaryOperation(phi),
+ phi_(phi), relation_(relation), operand_index_(operand_index) {
+ }
+
+ // We need to store the phi both here and in the instruction operand because
+ // the operand can change if a new idef of the phi is added between the phi
+ // and this instruction (inserting an idef updates every use).
+ HPhi* phi_;
+ NumericRelation relation_;
+ int operand_index_;
+};
+
+
class HArgumentsObject: public HTemplateInstruction<0> {
public:
HArgumentsObject() {
@@ -2568,8 +3208,17 @@ class HArgumentsObject: public HTemplateInstruction<0> {
class HConstant: public HTemplateInstruction<0> {
public:
HConstant(Handle<Object> handle, Representation r);
- HConstant(int32_t value, Representation r);
- HConstant(double value, Representation r);
+ HConstant(int32_t value,
+ Representation r,
+ Handle<Object> optional_handle = Handle<Object>::null());
+ HConstant(double value,
+ Representation r,
+ Handle<Object> optional_handle = Handle<Object>::null());
+ HConstant(Handle<Object> handle,
+ Representation r,
+ HType type,
+ bool is_internalized_string,
+ bool boolean_value);
Handle<Object> handle() {
if (handle_.is_null()) {
@@ -2594,18 +3243,20 @@ class HConstant: public HTemplateInstruction<0> {
}
ASSERT(!handle_.is_null());
- Heap* heap = HEAP;
+ Heap* heap = isolate()->heap();
// We should have handled minus_zero_value and nan_value in the
// has_double_value_ clause above.
+ // Dereferencing is safe to compare against immovable singletons.
+ HandleDereferenceGuard allow_handle_deref(isolate(),
+ HandleDereferenceGuard::ALLOW);
ASSERT(*handle_ != heap->minus_zero_value());
ASSERT(*handle_ != heap->nan_value());
- if (*handle_ == heap->undefined_value()) return true;
- if (*handle_ == heap->null_value()) return true;
- if (*handle_ == heap->true_value()) return true;
- if (*handle_ == heap->false_value()) return true;
- if (*handle_ == heap->the_hole_value()) return true;
- if (*handle_ == heap->empty_string()) return true;
- return false;
+ return *handle_ == heap->undefined_value() ||
+ *handle_ == heap->null_value() ||
+ *handle_ == heap->true_value() ||
+ *handle_ == heap->false_value() ||
+ *handle_ == heap->the_hole_value() ||
+ *handle_ == heap->empty_string();
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -2617,7 +3268,6 @@ class HConstant: public HTemplateInstruction<0> {
}
virtual bool EmitAtUses() { return !representation().IsDouble(); }
- virtual HValue* Canonicalize();
virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType();
bool IsInteger() { return handle()->IsSmi(); }
@@ -2628,6 +3278,9 @@ class HConstant: public HTemplateInstruction<0> {
ASSERT(HasInteger32Value());
return int32_value_;
}
+ bool HasSmiValue() const {
+ return HasInteger32Value() && Smi::IsValid(Integer32Value());
+ }
bool HasDoubleValue() const { return has_double_value_; }
double DoubleValue() const {
ASSERT(HasDoubleValue());
@@ -2641,8 +3294,20 @@ class HConstant: public HTemplateInstruction<0> {
// representation of the number in int32_value_.
return int32_value_;
}
+ bool HasStringValue() const {
+ if (has_double_value_ || has_int32_value_) return false;
+ ASSERT(!handle_.is_null());
+ return type_from_value_.IsString();
+ }
+ Handle<String> StringValue() const {
+ ASSERT(HasStringValue());
+ return Handle<String>::cast(handle_);
+ }
+ bool HasInternalizedStringValue() const {
+ return HasStringValue() && is_internalized_string_;
+ }
- bool ToBoolean();
+ bool BooleanValue() const { return boolean_value_; }
bool IsUint32() {
return HasInteger32Value() && (Integer32Value() >= 0);
@@ -2658,6 +3323,11 @@ class HConstant: public HTemplateInstruction<0> {
hash = static_cast<intptr_t>(BitCast<int64_t>(double_value_));
} else {
ASSERT(!handle_.is_null());
+ // Dereferencing to use the object's raw address for hashing is safe.
+ HandleDereferenceGuard allow_handle_deref(isolate(),
+ HandleDereferenceGuard::ALLOW);
+ SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) ||
+ !isolate()->optimizing_compiler_thread()->IsOptimizerThread());
hash = reinterpret_cast<intptr_t>(*handle_);
}
@@ -2685,11 +3355,13 @@ class HConstant: public HTemplateInstruction<0> {
} else {
ASSERT(!handle_.is_null());
return !other_constant->handle_.is_null() &&
- *handle_ == *other_constant->handle_;
+ handle_.is_identical_to(other_constant->handle_);
}
}
private:
+ void Initialize(Representation r);
+
virtual bool IsDeletable() const { return true; }
// If this is a numerical constant, handle_ either points to to the
@@ -2705,18 +3377,24 @@ class HConstant: public HTemplateInstruction<0> {
// not the converse.
bool has_int32_value_ : 1;
bool has_double_value_ : 1;
+ bool is_internalized_string_ : 1; // TODO(yangguo): make this part of HType.
+ bool boolean_value_ : 1;
int32_t int32_value_;
double double_value_;
+ HType type_from_value_;
};
class HBinaryOperation: public HTemplateInstruction<3> {
public:
- HBinaryOperation(HValue* context, HValue* left, HValue* right) {
+ HBinaryOperation(HValue* context, HValue* left, HValue* right)
+ : observed_output_representation_(Representation::None()) {
ASSERT(left != NULL && right != NULL);
SetOperandAt(0, context);
SetOperandAt(1, left);
SetOperandAt(2, right);
+ observed_input_representation_[0] = Representation::None();
+ observed_input_representation_[1] = Representation::None();
}
HValue* context() { return OperandAt(0); }
@@ -2735,11 +3413,34 @@ class HBinaryOperation: public HTemplateInstruction<3> {
return right();
}
+ void set_observed_input_representation(Representation left,
+ Representation right) {
+ observed_input_representation_[0] = left;
+ observed_input_representation_[1] = right;
+ }
+
+ virtual void initialize_output_representation(Representation observed) {
+ observed_output_representation_ = observed;
+ }
+
+ virtual Representation observed_input_representation(int index) {
+ if (index == 0) return Representation::Tagged();
+ return observed_input_representation_[index - 1];
+ }
+
+ virtual void InferRepresentation(HInferRepresentation* h_infer);
+ virtual Representation RepresentationFromInputs();
+ virtual void AssumeRepresentation(Representation r);
+
virtual bool IsCommutative() const { return false; }
virtual void PrintDataTo(StringStream* stream);
DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
+
+ private:
+ Representation observed_input_representation_[2];
+ Representation observed_output_representation_;
};
@@ -2879,49 +3580,147 @@ enum BoundsCheckKeyMode {
};
+class HBoundsCheckBaseIndexInformation;
+
+
class HBoundsCheck: public HTemplateInstruction<2> {
public:
- HBoundsCheck(HValue* index, HValue* length,
- BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY)
- : key_mode_(key_mode) {
+ // Normally HBoundsCheck should be created using the
+ // HGraphBuilder::AddBoundsCheck() helper, which also guards the index with
+ // a HCheckSmiOrInt32 check.
+ // However when building stubs, where we know that the arguments are Int32,
+ // it makes sense to invoke this constructor directly.
+ HBoundsCheck(HValue* index,
+ HValue* length,
+ BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY,
+ Representation r = Representation::None())
+ : key_mode_(key_mode), skip_check_(false),
+ base_(NULL), offset_(0), scale_(0),
+ responsibility_direction_(DIRECTION_NONE) {
SetOperandAt(0, index);
SetOperandAt(1, length);
- set_representation(Representation::Integer32());
+ if (r.IsNone()) {
+ // In the normal compilation pipeline the representation is flexible
+ // (see InferRepresentation).
+ SetFlag(kFlexibleRepresentation);
+ } else {
+ // When compiling stubs we want to set the representation explicitly
+ // so the compilation pipeline can skip the HInferRepresentation phase.
+ set_representation(r);
+ }
SetFlag(kUseGVN);
}
- virtual Representation RequiredInputRepresentation(int arg_index) {
- if (key_mode_ == DONT_ALLOW_SMI_KEY ||
- !length()->representation().IsTagged()) {
- return Representation::Integer32();
- }
- // If the index is tagged and isn't constant, then allow the length
- // to be tagged, since it is usually already tagged from loading it out of
- // the length field of a JSArray. This allows for direct comparison without
- // untagging.
- if (index()->representation().IsTagged() && !index()->IsConstant()) {
- return Representation::Tagged();
- }
- // Also allow the length to be tagged if the index is constant, because
- // it can be tagged to allow direct comparison.
- if (index()->IsConstant() &&
- index()->representation().IsInteger32() &&
- arg_index == 1) {
- return Representation::Tagged();
+ bool skip_check() { return skip_check_; }
+ void set_skip_check(bool skip_check) { skip_check_ = skip_check; }
+ HValue* base() { return base_; }
+ int offset() { return offset_; }
+ int scale() { return scale_; }
+ bool index_can_increase() {
+ return (responsibility_direction_ & DIRECTION_LOWER) == 0;
+ }
+ bool index_can_decrease() {
+ return (responsibility_direction_ & DIRECTION_UPPER) == 0;
+ }
+
+ void ApplyIndexChange();
+ bool DetectCompoundIndex() {
+ ASSERT(base() == NULL);
+
+ DecompositionResult decomposition;
+ if (index()->TryDecompose(&decomposition)) {
+ base_ = decomposition.base();
+ offset_ = decomposition.offset();
+ scale_ = decomposition.scale();
+ return true;
+ } else {
+ base_ = index();
+ offset_ = 0;
+ scale_ = 0;
+ return false;
}
+ }
+
+ virtual Representation RequiredInputRepresentation(int arg_index) {
+ return representation();
+ }
+ virtual Representation observed_input_representation(int index) {
return Representation::Integer32();
}
+ virtual bool IsRelationTrueInternal(NumericRelation relation,
+ HValue* related_value,
+ int offset = 0,
+ int scale = 0);
+
virtual void PrintDataTo(StringStream* stream);
+ virtual void InferRepresentation(HInferRepresentation* h_infer);
HValue* index() { return OperandAt(0); }
HValue* length() { return OperandAt(1); }
+ virtual int RedefinedOperandIndex() { return 0; }
+ virtual bool IsPurelyInformativeDefinition() { return skip_check(); }
+ virtual void AddInformativeDefinitions();
+
DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
protected:
+ friend class HBoundsCheckBaseIndexInformation;
+
+ virtual void SetResponsibilityForRange(RangeGuaranteeDirection direction) {
+ responsibility_direction_ = static_cast<RangeGuaranteeDirection>(
+ responsibility_direction_ | direction);
+ }
+
virtual bool DataEquals(HValue* other) { return true; }
+ virtual void TryGuaranteeRangeChanging(RangeEvaluationContext* context);
BoundsCheckKeyMode key_mode_;
+ bool skip_check_;
+ HValue* base_;
+ int offset_;
+ int scale_;
+ RangeGuaranteeDirection responsibility_direction_;
+};
+
+
+class HBoundsCheckBaseIndexInformation: public HTemplateInstruction<2> {
+ public:
+ explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
+ DecompositionResult decomposition;
+ if (check->index()->TryDecompose(&decomposition)) {
+ SetOperandAt(0, decomposition.base());
+ SetOperandAt(1, check);
+ } else {
+ UNREACHABLE();
+ }
+ }
+
+ HValue* base_index() { return OperandAt(0); }
+ HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
+
+ DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
+
+ virtual Representation RequiredInputRepresentation(int arg_index) {
+ return representation();
+ }
+
+ virtual bool IsRelationTrueInternal(NumericRelation relation,
+ HValue* related_value,
+ int offset = 0,
+ int scale = 0);
+ virtual void PrintDataTo(StringStream* stream);
+
+ virtual int RedefinedOperandIndex() { return 0; }
+ virtual bool IsPurelyInformativeDefinition() { return true; }
+
+ protected:
+ virtual void SetResponsibilityForRange(RangeGuaranteeDirection direction) {
+ bounds_check()->SetResponsibilityForRange(direction);
+ }
+ virtual void TryGuaranteeRangeChanging(RangeEvaluationContext* context) {
+ bounds_check()->TryGuaranteeRangeChanging(context);
+ }
};
@@ -2929,12 +3728,9 @@ class HBitwiseBinaryOperation: public HBinaryOperation {
public:
HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right)
: HBinaryOperation(context, left, right) {
- set_representation(Representation::Tagged());
SetFlag(kFlexibleRepresentation);
+ SetFlag(kTruncatingToInt32);
SetAllSideEffects();
- observed_input_representation_[0] = Representation::Tagged();
- observed_input_representation_[1] = Representation::None();
- observed_input_representation_[2] = Representation::None();
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -2947,28 +3743,32 @@ class HBitwiseBinaryOperation: public HBinaryOperation {
if (!to.IsTagged()) {
ASSERT(to.IsInteger32());
ClearAllSideEffects();
- SetFlag(kTruncatingToInt32);
SetFlag(kUseGVN);
+ } else {
+ SetAllSideEffects();
+ ClearFlag(kUseGVN);
}
}
- virtual HType CalculateInferredType();
-
- virtual Representation ObservedInputRepresentation(int index) {
- return observed_input_representation_[index];
+ virtual void UpdateRepresentation(Representation new_rep,
+ HInferRepresentation* h_infer,
+ const char* reason) {
+ // We only generate either int32 or generic tagged bitwise operations.
+ if (new_rep.IsDouble()) new_rep = Representation::Integer32();
+ HValue::UpdateRepresentation(new_rep, h_infer, reason);
}
- void InitializeObservedInputRepresentation(Representation r) {
- observed_input_representation_[1] = r;
- observed_input_representation_[2] = r;
+ virtual void initialize_output_representation(Representation observed) {
+ if (observed.IsDouble()) observed = Representation::Integer32();
+ HBinaryOperation::initialize_output_representation(observed);
}
+ virtual HType CalculateInferredType();
+
DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
private:
virtual bool IsDeletable() const { return true; }
-
- Representation observed_input_representation_[3];
};
@@ -2979,6 +3779,9 @@ class HMathFloorOfDiv: public HBinaryOperation {
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
SetFlag(kCanOverflow);
+ if (!right->IsConstant()) {
+ SetFlag(kCanBeDivByZero);
+ }
}
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
@@ -3001,13 +3804,15 @@ class HArithmeticBinaryOperation: public HBinaryOperation {
public:
HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right)
: HBinaryOperation(context, left, right) {
- set_representation(Representation::Tagged());
- SetFlag(kFlexibleRepresentation);
SetAllSideEffects();
+ SetFlag(kFlexibleRepresentation);
}
virtual void RepresentationChanged(Representation to) {
- if (!to.IsTagged()) {
+ if (to.IsTagged()) {
+ SetAllSideEffects();
+ ClearFlag(kUseGVN);
+ } else {
ClearAllSideEffects();
SetFlag(kUseGVN);
}
@@ -3020,13 +3825,6 @@ class HArithmeticBinaryOperation: public HBinaryOperation {
: representation();
}
- virtual Representation InferredRepresentation() {
- if (left()->representation().Equals(right()->representation())) {
- return left()->representation();
- }
- return HValue::InferredRepresentation();
- }
-
private:
virtual bool IsDeletable() const { return true; }
};
@@ -3045,11 +3843,9 @@ class HCompareGeneric: public HBinaryOperation {
}
virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
- }
-
- Representation GetInputRepresentation() const {
- return Representation::Tagged();
+ return index == 0
+ ? Representation::Tagged()
+ : representation();
}
Token::Value token() const { return token_; }
@@ -3068,6 +3864,7 @@ class HCompareIDAndBranch: public HTemplateControlInstruction<2, 2> {
public:
HCompareIDAndBranch(HValue* left, HValue* right, Token::Value token)
: token_(token) {
+ SetFlag(kFlexibleRepresentation);
ASSERT(Token::IsCompareOp(token));
SetOperandAt(0, left);
SetOperandAt(1, right);
@@ -3077,20 +3874,28 @@ class HCompareIDAndBranch: public HTemplateControlInstruction<2, 2> {
HValue* right() { return OperandAt(1); }
Token::Value token() const { return token_; }
- void SetInputRepresentation(Representation r);
- Representation GetInputRepresentation() const {
- return input_representation_;
+ void set_observed_input_representation(Representation left,
+ Representation right) {
+ observed_input_representation_[0] = left;
+ observed_input_representation_[1] = right;
}
+ virtual void InferRepresentation(HInferRepresentation* h_infer);
+
virtual Representation RequiredInputRepresentation(int index) {
- return input_representation_;
+ return representation();
+ }
+ virtual Representation observed_input_representation(int index) {
+ return observed_input_representation_[index];
}
virtual void PrintDataTo(StringStream* stream);
+ virtual void AddInformativeDefinitions();
+
DECLARE_CONCRETE_INSTRUCTION(CompareIDAndBranch)
private:
- Representation input_representation_;
+ Representation observed_input_representation_[2];
Token::Value token_;
};
@@ -3151,6 +3956,9 @@ class HIsNilAndBranch: public HUnaryControlInstruction {
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+ virtual Representation observed_input_representation(int index) {
+ return Representation::Tagged();
+ }
DECLARE_CONCRETE_INSTRUCTION(IsNilAndBranch)
@@ -3410,16 +4218,30 @@ class HInstanceOfKnownGlobal: public HTemplateInstruction<2> {
};
-class HPower: public HTemplateInstruction<2> {
+// TODO(mstarzinger): This instruction should be modeled as a load of the map
+// field followed by a load of the instance size field once HLoadNamedField is
+// flexible enough to accommodate byte-field loads.
+class HInstanceSize: public HTemplateInstruction<1> {
public:
- HPower(HValue* left, HValue* right) {
- SetOperandAt(0, left);
- SetOperandAt(1, right);
- set_representation(Representation::Double());
- SetFlag(kUseGVN);
- SetGVNFlag(kChangesNewSpacePromotion);
+ explicit HInstanceSize(HValue* object) {
+ SetOperandAt(0, object);
+ set_representation(Representation::Integer32());
}
+ HValue* object() { return OperandAt(0); }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(InstanceSize)
+};
+
+
+class HPower: public HTemplateInstruction<2> {
+ public:
+ static HInstruction* New(Zone* zone, HValue* left, HValue* right);
+
HValue* left() { return OperandAt(0); }
HValue* right() const { return OperandAt(1); }
@@ -3428,6 +4250,9 @@ class HPower: public HTemplateInstruction<2> {
? Representation::Double()
: Representation::None();
}
+ virtual Representation observed_input_representation(int index) {
+ return RequiredInputRepresentation(index);
+ }
DECLARE_CONCRETE_INSTRUCTION(Power)
@@ -3435,6 +4260,14 @@ class HPower: public HTemplateInstruction<2> {
virtual bool DataEquals(HValue* other) { return true; }
private:
+ HPower(HValue* left, HValue* right) {
+ SetOperandAt(0, left);
+ SetOperandAt(1, right);
+ set_representation(Representation::Double());
+ SetFlag(kUseGVN);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+
virtual bool IsDeletable() const {
return !right()->representation().IsTagged();
}
@@ -3463,10 +4296,10 @@ class HRandom: public HTemplateInstruction<1> {
class HAdd: public HArithmeticBinaryOperation {
public:
- HAdd(HValue* context, HValue* left, HValue* right)
- : HArithmeticBinaryOperation(context, left, right) {
- SetFlag(kCanOverflow);
- }
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
// 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).
@@ -3476,39 +4309,56 @@ class HAdd: public HArithmeticBinaryOperation {
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
- static HInstruction* NewHAdd(Zone* zone,
- HValue* context,
- HValue* left,
- HValue* right);
-
virtual HType CalculateInferredType();
virtual HValue* Canonicalize();
+ virtual bool TryDecompose(DecompositionResult* decomposition) {
+ if (left()->IsInteger32Constant()) {
+ decomposition->Apply(right(), left()->GetInteger32Constant());
+ return true;
+ } else if (right()->IsInteger32Constant()) {
+ decomposition->Apply(left(), right()->GetInteger32Constant());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
DECLARE_CONCRETE_INSTRUCTION(Add)
protected:
virtual bool DataEquals(HValue* other) { return true; }
virtual Range* InferRange(Zone* zone);
+
+ private:
+ HAdd(HValue* context, HValue* left, HValue* right)
+ : HArithmeticBinaryOperation(context, left, right) {
+ SetFlag(kCanOverflow);
+ }
};
class HSub: public HArithmeticBinaryOperation {
public:
- HSub(HValue* context, HValue* left, HValue* right)
- : HArithmeticBinaryOperation(context, left, right) {
- SetFlag(kCanOverflow);
- }
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
virtual HValue* Canonicalize();
- static HInstruction* NewHSub(Zone* zone,
- HValue* context,
- HValue* left,
- HValue* right);
+ virtual bool TryDecompose(DecompositionResult* decomposition) {
+ if (right()->IsInteger32Constant()) {
+ decomposition->Apply(left(), -right()->GetInteger32Constant());
+ return true;
+ } else {
+ return false;
+ }
+ }
DECLARE_CONCRETE_INSTRUCTION(Sub)
@@ -3516,15 +4366,21 @@ class HSub: public HArithmeticBinaryOperation {
virtual bool DataEquals(HValue* other) { return true; }
virtual Range* InferRange(Zone* zone);
+
+ private:
+ HSub(HValue* context, HValue* left, HValue* right)
+ : HArithmeticBinaryOperation(context, left, right) {
+ SetFlag(kCanOverflow);
+ }
};
class HMul: public HArithmeticBinaryOperation {
public:
- HMul(HValue* context, HValue* left, HValue* right)
- : HArithmeticBinaryOperation(context, left, right) {
- SetFlag(kCanOverflow);
- }
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
@@ -3533,26 +4389,27 @@ class HMul: public HArithmeticBinaryOperation {
return !representation().IsTagged();
}
- static HInstruction* NewHMul(Zone* zone,
- HValue* context,
- HValue* left,
- HValue* right);
-
DECLARE_CONCRETE_INSTRUCTION(Mul)
protected:
virtual bool DataEquals(HValue* other) { return true; }
virtual Range* InferRange(Zone* zone);
+
+ private:
+ HMul(HValue* context, HValue* left, HValue* right)
+ : HArithmeticBinaryOperation(context, left, right) {
+ SetFlag(kCanOverflow);
+ }
};
class HMod: public HArithmeticBinaryOperation {
public:
- HMod(HValue* context, HValue* left, HValue* right)
- : HArithmeticBinaryOperation(context, left, right) {
- SetFlag(kCanBeDivByZero);
- }
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
bool HasPowerOf2Divisor() {
if (right()->IsConstant() &&
@@ -3566,41 +4423,53 @@ class HMod: public HArithmeticBinaryOperation {
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
- static HInstruction* NewHMod(Zone* zone,
- HValue* context,
- HValue* left,
- HValue* right);
-
DECLARE_CONCRETE_INSTRUCTION(Mod)
protected:
virtual bool DataEquals(HValue* other) { return true; }
virtual Range* InferRange(Zone* zone);
+
+ private:
+ HMod(HValue* context, HValue* left, HValue* right)
+ : HArithmeticBinaryOperation(context, left, right) {
+ SetFlag(kCanBeDivByZero);
+ }
};
class HDiv: public HArithmeticBinaryOperation {
public:
- HDiv(HValue* context, HValue* left, HValue* right)
- : HArithmeticBinaryOperation(context, left, right) {
- SetFlag(kCanBeDivByZero);
- SetFlag(kCanOverflow);
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
+
+ bool HasPowerOf2Divisor() {
+ if (right()->IsConstant() &&
+ HConstant::cast(right())->HasInteger32Value()) {
+ int32_t value = HConstant::cast(right())->Integer32Value();
+ return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value));
+ }
+
+ return false;
}
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
- static HInstruction* NewHDiv(Zone* zone,
- HValue* context,
- HValue* left,
- HValue* right);
-
DECLARE_CONCRETE_INSTRUCTION(Div)
protected:
virtual bool DataEquals(HValue* other) { return true; }
virtual Range* InferRange(Zone* zone);
+
+ private:
+ HDiv(HValue* context, HValue* left, HValue* right)
+ : HArithmeticBinaryOperation(context, left, right) {
+ SetFlag(kCanBeDivByZero);
+ SetFlag(kCanOverflow);
+ }
};
@@ -3608,19 +4477,28 @@ class HMathMinMax: public HArithmeticBinaryOperation {
public:
enum Operation { kMathMin, kMathMax };
- HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
- : HArithmeticBinaryOperation(context, left, right),
- operation_(op) { }
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right,
+ Operation op);
virtual Representation RequiredInputRepresentation(int index) {
- return index == 0
- ? Representation::Tagged()
- : representation();
- }
+ return index == 0 ? Representation::Tagged()
+ : representation();
+ }
+
+ virtual Representation observed_input_representation(int index) {
+ return RequiredInputRepresentation(index);
+ }
- virtual Representation InferredRepresentation() {
- if (left()->representation().IsInteger32() &&
- right()->representation().IsInteger32()) {
+ virtual void InferRepresentation(HInferRepresentation* h_infer);
+
+ virtual Representation RepresentationFromInputs() {
+ Representation left_rep = left()->representation();
+ Representation right_rep = right()->representation();
+ if ((left_rep.IsNone() || left_rep.IsInteger32()) &&
+ (right_rep.IsNone() || right_rep.IsInteger32())) {
return Representation::Integer32();
}
return Representation::Double();
@@ -3641,18 +4519,21 @@ class HMathMinMax: public HArithmeticBinaryOperation {
virtual Range* InferRange(Zone* zone);
private:
+ HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
+ : HArithmeticBinaryOperation(context, left, right),
+ operation_(op) { }
+
Operation operation_;
};
class HBitwise: public HBitwiseBinaryOperation {
public:
- HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right)
- : HBitwiseBinaryOperation(context, left, right), op_(op) {
- ASSERT(op == Token::BIT_AND ||
- op == Token::BIT_OR ||
- op == Token::BIT_XOR);
- }
+ static HInstruction* New(Zone* zone,
+ Token::Value op,
+ HValue* context,
+ HValue* left,
+ HValue* right);
Token::Value op() const { return op_; }
@@ -3660,12 +4541,6 @@ class HBitwise: public HBitwiseBinaryOperation {
virtual HValue* Canonicalize();
- static HInstruction* NewHBitwise(Zone* zone,
- Token::Value op,
- HValue* context,
- HValue* left,
- HValue* right);
-
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(Bitwise)
@@ -3678,61 +4553,107 @@ class HBitwise: public HBitwiseBinaryOperation {
virtual Range* InferRange(Zone* zone);
private:
+ HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right)
+ : HBitwiseBinaryOperation(context, left, right), op_(op) {
+ ASSERT(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
+ }
+
Token::Value op_;
};
class HShl: public HBitwiseBinaryOperation {
public:
- HShl(HValue* context, HValue* left, HValue* right)
- : HBitwiseBinaryOperation(context, left, right) { }
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
virtual Range* InferRange(Zone* zone);
- static HInstruction* NewHShl(Zone* zone,
- HValue* context,
- HValue* left,
- HValue* right);
-
DECLARE_CONCRETE_INSTRUCTION(Shl)
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ HShl(HValue* context, HValue* left, HValue* right)
+ : HBitwiseBinaryOperation(context, left, right) { }
};
class HShr: public HBitwiseBinaryOperation {
public:
- HShr(HValue* context, HValue* left, HValue* right)
- : HBitwiseBinaryOperation(context, left, right) { }
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
+
+ virtual bool TryDecompose(DecompositionResult* decomposition) {
+ if (right()->IsInteger32Constant()) {
+ if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
+ // This is intended to look for HAdd and HSub, to handle compounds
+ // like ((base + offset) >> scale) with one single decomposition.
+ left()->TryDecompose(decomposition);
+ return true;
+ }
+ }
+ return false;
+ }
virtual Range* InferRange(Zone* zone);
- static HInstruction* NewHShr(Zone* zone,
- HValue* context,
- HValue* left,
- HValue* right);
-
DECLARE_CONCRETE_INSTRUCTION(Shr)
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ HShr(HValue* context, HValue* left, HValue* right)
+ : HBitwiseBinaryOperation(context, left, right) { }
};
class HSar: public HBitwiseBinaryOperation {
public:
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
+
+ virtual bool TryDecompose(DecompositionResult* decomposition) {
+ if (right()->IsInteger32Constant()) {
+ if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
+ // This is intended to look for HAdd and HSub, to handle compounds
+ // like ((base + offset) >> scale) with one single decomposition.
+ left()->TryDecompose(decomposition);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ virtual Range* InferRange(Zone* zone);
+
+ DECLARE_CONCRETE_INSTRUCTION(Sar)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
HSar(HValue* context, HValue* left, HValue* right)
: HBitwiseBinaryOperation(context, left, right) { }
+};
- virtual Range* InferRange(Zone* zone);
- static HInstruction* NewHSar(Zone* zone,
- HValue* context,
- HValue* left,
- HValue* right);
+class HRor: public HBitwiseBinaryOperation {
+ public:
+ HRor(HValue* context, HValue* left, HValue* right)
+ : HBitwiseBinaryOperation(context, left, right) {
+ ChangeRepresentation(Representation::Integer32());
+ }
- DECLARE_CONCRETE_INSTRUCTION(Sar)
+ DECLARE_CONCRETE_INSTRUCTION(Ror)
protected:
virtual bool DataEquals(HValue* other) { return true; }
@@ -3760,11 +4681,20 @@ class HOsrEntry: public HTemplateInstruction<0> {
class HParameter: public HTemplateInstruction<0> {
public:
- explicit HParameter(unsigned index) : index_(index) {
+ enum ParameterKind {
+ STACK_PARAMETER,
+ REGISTER_PARAMETER
+ };
+
+ explicit HParameter(unsigned index,
+ ParameterKind kind = STACK_PARAMETER)
+ : index_(index),
+ kind_(kind) {
set_representation(Representation::Tagged());
}
unsigned index() const { return index_; }
+ ParameterKind kind() const { return kind_; }
virtual void PrintDataTo(StringStream* stream);
@@ -3776,6 +4706,7 @@ class HParameter: public HTemplateInstruction<0> {
private:
unsigned index_;
+ ParameterKind kind_;
};
@@ -3847,13 +4778,18 @@ class HLoadGlobalCell: public HTemplateInstruction<0> {
SetGVNFlag(kDependsOnGlobalVars);
}
- Handle<JSGlobalPropertyCell> cell() const { return cell_; }
+ Handle<JSGlobalPropertyCell> cell() const { return cell_; }
bool RequiresHoleCheck() const;
virtual void PrintDataTo(StringStream* stream);
virtual intptr_t Hashcode() {
ASSERT_ALLOCATION_DISABLED;
+ // Dereferencing to use the object's raw address for hashing is safe.
+ HandleDereferenceGuard allow_handle_deref(isolate(),
+ HandleDereferenceGuard::ALLOW);
+ SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) ||
+ !isolate()->optimizing_compiler_thread()->IsOptimizerThread());
return reinterpret_cast<intptr_t>(*cell_);
}
@@ -3910,6 +4846,132 @@ class HLoadGlobalGeneric: public HTemplateInstruction<2> {
};
+class HAllocateObject: public HTemplateInstruction<1> {
+ public:
+ HAllocateObject(HValue* context, Handle<JSFunction> constructor)
+ : constructor_(constructor) {
+ SetOperandAt(0, context);
+ set_representation(Representation::Tagged());
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+
+ // Maximum instance size for which allocations will be inlined.
+ static const int kMaxSize = 64 * kPointerSize;
+
+ HValue* context() { return OperandAt(0); }
+ Handle<JSFunction> constructor() { return constructor_; }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+ virtual Handle<Map> GetMonomorphicJSObjectMap() {
+ ASSERT(constructor()->has_initial_map());
+ return Handle<Map>(constructor()->initial_map());
+ }
+ virtual HType CalculateInferredType();
+
+ DECLARE_CONCRETE_INSTRUCTION(AllocateObject)
+
+ private:
+ // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
+ // virtual bool IsDeletable() const { return true; }
+
+ Handle<JSFunction> constructor_;
+};
+
+
+class HAllocate: public HTemplateInstruction<2> {
+ public:
+ enum Flags {
+ CAN_ALLOCATE_IN_NEW_SPACE = 1 << 0,
+ CAN_ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1,
+ CAN_ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2,
+ ALLOCATE_DOUBLE_ALIGNED = 1 << 3
+ };
+
+ HAllocate(HValue* context, HValue* size, HType type, Flags flags)
+ : type_(type),
+ flags_(flags) {
+ ASSERT((flags & CAN_ALLOCATE_IN_OLD_DATA_SPACE) == 0); // unimplemented
+ SetOperandAt(0, context);
+ SetOperandAt(1, size);
+ set_representation(Representation::Tagged());
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+
+ HValue* context() { return OperandAt(0); }
+ HValue* size() { return OperandAt(1); }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ if (index == 0) {
+ return Representation::Tagged();
+ } else {
+ return Representation::Integer32();
+ }
+ }
+
+ virtual HType CalculateInferredType();
+
+ bool CanAllocateInNewSpace() const {
+ return (flags_ & CAN_ALLOCATE_IN_NEW_SPACE) != 0;
+ }
+
+ bool CanAllocateInOldDataSpace() const {
+ return (flags_ & CAN_ALLOCATE_IN_OLD_DATA_SPACE) != 0;
+ }
+
+ bool CanAllocateInOldPointerSpace() const {
+ return (flags_ & CAN_ALLOCATE_IN_OLD_POINTER_SPACE) != 0;
+ }
+
+ bool CanAllocateInOldSpace() const {
+ return CanAllocateInOldDataSpace() ||
+ CanAllocateInOldPointerSpace();
+ }
+
+ bool GuaranteedInNewSpace() const {
+ return CanAllocateInNewSpace() && !CanAllocateInOldSpace();
+ }
+
+ bool MustAllocateDoubleAligned() const {
+ return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
+ }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ DECLARE_CONCRETE_INSTRUCTION(Allocate)
+
+ private:
+ HType type_;
+ Flags flags_;
+};
+
+
+class HInnerAllocatedObject: public HTemplateInstruction<1> {
+ public:
+ HInnerAllocatedObject(HValue* value, int offset)
+ : offset_(offset) {
+ ASSERT(value->IsAllocate());
+ SetOperandAt(0, value);
+ set_representation(Representation::Tagged());
+ }
+
+ HValue* base_object() { return OperandAt(0); }
+ int offset() { return offset_; }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
+
+ private:
+ int offset_;
+};
+
+
inline bool StoringValueNeedsWriteBarrier(HValue* value) {
return !value->type().IsBoolean()
&& !value->type().IsSmi()
@@ -3919,7 +4981,18 @@ inline bool StoringValueNeedsWriteBarrier(HValue* value) {
inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
HValue* new_space_dominator) {
- return !object->IsAllocateObject() || (object != new_space_dominator);
+ if (object->IsInnerAllocatedObject()) {
+ return ReceiverObjectNeedsWriteBarrier(
+ HInnerAllocatedObject::cast(object)->base_object(),
+ new_space_dominator);
+ }
+ if (object != new_space_dominator) return true;
+ if (object->IsFastLiteral()) return false;
+ if (object->IsAllocateObject()) return false;
+ if (object->IsAllocate()) {
+ return !HAllocate::cast(object)->GuaranteedInNewSpace();
+ }
+ return true;
}
@@ -4243,33 +5316,79 @@ class ArrayInstructionInterface {
virtual bool IsDehoisted() = 0;
virtual void SetDehoisted(bool is_dehoisted) = 0;
virtual ~ArrayInstructionInterface() { };
+
+ static Representation KeyedAccessIndexRequirement(Representation r) {
+ return r.IsInteger32() ? Representation::Integer32()
+ : Representation::Tagged();
+ }
};
-class HLoadKeyedFastElement
+
+enum LoadKeyedHoleMode {
+ NEVER_RETURN_HOLE,
+ ALLOW_RETURN_HOLE
+};
+
+
+class HLoadKeyed
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
- HLoadKeyedFastElement(HValue* obj,
- HValue* key,
- HValue* dependency,
- ElementsKind elements_kind = FAST_ELEMENTS)
+ HLoadKeyed(HValue* obj,
+ HValue* key,
+ HValue* dependency,
+ ElementsKind elements_kind,
+ LoadKeyedHoleMode mode = NEVER_RETURN_HOLE)
: bit_field_(0) {
- ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
- bit_field_ = ElementsKindField::encode(elements_kind);
- if (IsFastSmiElementsKind(elements_kind) &&
- IsFastPackedElementsKind(elements_kind)) {
- set_type(HType::Smi());
- }
+ bit_field_ = ElementsKindField::encode(elements_kind) |
+ HoleModeField::encode(mode);
+
SetOperandAt(0, obj);
SetOperandAt(1, key);
- SetOperandAt(2, dependency);
- set_representation(Representation::Tagged());
- SetGVNFlag(kDependsOnArrayElements);
+ SetOperandAt(2, dependency != NULL ? dependency : obj);
+
+ if (!is_external()) {
+ // I can detect the case between storing double (holey and fast) and
+ // smi/object by looking at elements_kind_.
+ ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
+ IsFastDoubleElementsKind(elements_kind));
+
+ if (IsFastSmiOrObjectElementsKind(elements_kind)) {
+ if (IsFastSmiElementsKind(elements_kind)) {
+ set_type(HType::Smi());
+ }
+
+ set_representation(Representation::Tagged());
+ SetGVNFlag(kDependsOnArrayElements);
+ } else {
+ set_representation(Representation::Double());
+ SetGVNFlag(kDependsOnDoubleArrayElements);
+ }
+ } else {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
+ set_representation(Representation::Double());
+ } else {
+ set_representation(Representation::Integer32());
+ }
+
+ SetGVNFlag(kDependsOnSpecializedArrayElements);
+ // Native code could change the specialized array.
+ SetGVNFlag(kDependsOnCalls);
+ }
+
SetFlag(kUseGVN);
}
- HValue* object() { return OperandAt(0); }
+ bool is_external() const {
+ return IsExternalArrayElementsKind(elements_kind());
+ }
+ HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
- HValue* dependency() { return OperandAt(2); }
+ HValue* dependency() {
+ ASSERT(HasDependency());
+ return OperandAt(2);
+ }
+ bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
uint32_t index_offset() { return IndexOffsetField::decode(bit_field_); }
void SetIndexOffset(uint32_t index_offset) {
bit_field_ = IndexOffsetField::update(bit_field_, index_offset);
@@ -4283,166 +5402,82 @@ class HLoadKeyedFastElement
ElementsKind elements_kind() const {
return ElementsKindField::decode(bit_field_);
}
+ LoadKeyedHoleMode hole_mode() const {
+ return HoleModeField::decode(bit_field_);
+ }
virtual Representation RequiredInputRepresentation(int index) {
- // The key is supposed to be Integer32.
- if (index == 0) return Representation::Tagged();
- if (index == 1) return Representation::Integer32();
+ // kind_fast: tagged[int32] (none)
+ // kind_double: tagged[int32] (none)
+ // kind_external: external[int32] (none)
+ if (index == 0) {
+ return is_external() ? Representation::External()
+ : Representation::Tagged();
+ }
+ if (index == 1) {
+ return ArrayInstructionInterface::KeyedAccessIndexRequirement(
+ OperandAt(1)->representation());
+ }
return Representation::None();
}
+ virtual Representation observed_input_representation(int index) {
+ return RequiredInputRepresentation(index);
+ }
+
virtual void PrintDataTo(StringStream* stream);
+ bool UsesMustHandleHole() const;
bool RequiresHoleCheck() const;
- DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement)
+ virtual Range* InferRange(Zone* zone);
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
protected:
virtual bool DataEquals(HValue* other) {
- if (!other->IsLoadKeyedFastElement()) return false;
- HLoadKeyedFastElement* other_load = HLoadKeyedFastElement::cast(other);
+ if (!other->IsLoadKeyed()) return false;
+ HLoadKeyed* other_load = HLoadKeyed::cast(other);
+
if (IsDehoisted() && index_offset() != other_load->index_offset())
return false;
return elements_kind() == other_load->elements_kind();
}
private:
- virtual bool IsDeletable() const { return !RequiresHoleCheck(); }
-
- class ElementsKindField: public BitField<ElementsKind, 0, 4> {};
- class IndexOffsetField: public BitField<uint32_t, 4, 27> {};
- class IsDehoistedField: public BitField<bool, 31, 1> {};
- uint32_t bit_field_;
-};
-
-
-enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK };
-
-
-class HLoadKeyedFastDoubleElement
- : public HTemplateInstruction<3>, public ArrayInstructionInterface {
- public:
- HLoadKeyedFastDoubleElement(
- HValue* elements,
- HValue* key,
- HValue* dependency,
- HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
- : index_offset_(0),
- is_dehoisted_(false),
- hole_check_mode_(hole_check_mode) {
- SetOperandAt(0, elements);
- SetOperandAt(1, key);
- SetOperandAt(2, dependency);
- set_representation(Representation::Double());
- SetGVNFlag(kDependsOnDoubleArrayElements);
- SetFlag(kUseGVN);
- }
-
- HValue* elements() { return OperandAt(0); }
- HValue* key() { return OperandAt(1); }
- HValue* dependency() { return OperandAt(2); }
- uint32_t index_offset() { return index_offset_; }
- void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
- HValue* GetKey() { return key(); }
- void SetKey(HValue* key) { SetOperandAt(1, key); }
- bool IsDehoisted() { return is_dehoisted_; }
- void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
-
- virtual Representation RequiredInputRepresentation(int index) {
- // The key is supposed to be Integer32.
- if (index == 0) return Representation::Tagged();
- if (index == 1) return Representation::Integer32();
- return Representation::None();
- }
-
- bool RequiresHoleCheck() const {
- return hole_check_mode_ == PERFORM_HOLE_CHECK;
- }
-
- virtual void PrintDataTo(StringStream* stream);
-
- DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement)
-
- protected:
- virtual bool DataEquals(HValue* other) {
- if (!other->IsLoadKeyedFastDoubleElement()) return false;
- HLoadKeyedFastDoubleElement* other_load =
- HLoadKeyedFastDoubleElement::cast(other);
- return hole_check_mode_ == other_load->hole_check_mode_;
- }
-
- private:
- virtual bool IsDeletable() const { return !RequiresHoleCheck(); }
-
- uint32_t index_offset_;
- bool is_dehoisted_;
- HoleCheckMode hole_check_mode_;
-};
-
-
-class HLoadKeyedSpecializedArrayElement
- : public HTemplateInstruction<3>, public ArrayInstructionInterface {
- public:
- HLoadKeyedSpecializedArrayElement(HValue* external_elements,
- HValue* key,
- HValue* dependency,
- ElementsKind elements_kind)
- : elements_kind_(elements_kind),
- index_offset_(0),
- is_dehoisted_(false) {
- SetOperandAt(0, external_elements);
- SetOperandAt(1, key);
- SetOperandAt(2, dependency);
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- set_representation(Representation::Double());
- } else {
- set_representation(Representation::Integer32());
- }
- SetGVNFlag(kDependsOnSpecializedArrayElements);
- // Native code could change the specialized array.
- SetGVNFlag(kDependsOnCalls);
- SetFlag(kUseGVN);
- }
-
- virtual void PrintDataTo(StringStream* stream);
-
- virtual Representation RequiredInputRepresentation(int index) {
- // The key is supposed to be Integer32.
- if (index == 0) return Representation::External();
- if (index == 1) return Representation::Integer32();
- return Representation::None();
+ virtual bool IsDeletable() const {
+ return !RequiresHoleCheck();
}
- HValue* external_pointer() { return OperandAt(0); }
- HValue* key() { return OperandAt(1); }
- HValue* dependency() { return OperandAt(2); }
- ElementsKind elements_kind() const { return elements_kind_; }
- uint32_t index_offset() { return index_offset_; }
- void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
- HValue* GetKey() { return key(); }
- void SetKey(HValue* key) { SetOperandAt(1, key); }
- bool IsDehoisted() { return is_dehoisted_; }
- void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
-
- virtual Range* InferRange(Zone* zone);
-
- DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement)
-
- protected:
- virtual bool DataEquals(HValue* other) {
- if (!other->IsLoadKeyedSpecializedArrayElement()) return false;
- HLoadKeyedSpecializedArrayElement* cast_other =
- HLoadKeyedSpecializedArrayElement::cast(other);
- return elements_kind_ == cast_other->elements_kind();
- }
+ // Establish some checks around our packed fields
+ enum LoadKeyedBits {
+ kBitsForElementsKind = 5,
+ kBitsForHoleMode = 1,
+ kBitsForIndexOffset = 25,
+ kBitsForIsDehoisted = 1,
- private:
- virtual bool IsDeletable() const { return true; }
+ kStartElementsKind = 0,
+ kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
+ kStartIndexOffset = kStartHoleMode + kBitsForHoleMode,
+ kStartIsDehoisted = kStartIndexOffset + kBitsForIndexOffset
+ };
- ElementsKind elements_kind_;
- uint32_t index_offset_;
- bool is_dehoisted_;
+ STATIC_ASSERT((kBitsForElementsKind + kBitsForIndexOffset +
+ kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
+ STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
+ class ElementsKindField:
+ public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
+ {}; // NOLINT
+ class HoleModeField:
+ public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
+ {}; // NOLINT
+ class IndexOffsetField:
+ public BitField<uint32_t, kStartIndexOffset, kBitsForIndexOffset>
+ {}; // NOLINT
+ class IsDehoistedField:
+ public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
+ {}; // NOLINT
+ uint32_t bit_field_;
};
@@ -4463,6 +5498,7 @@ class HLoadKeyedGeneric: public HTemplateInstruction<3> {
virtual void PrintDataTo(StringStream* stream);
virtual Representation RequiredInputRepresentation(int index) {
+ // tagged[tagged]
return Representation::Tagged();
}
@@ -4568,84 +5604,83 @@ class HStoreNamedGeneric: public HTemplateInstruction<3> {
};
-class HStoreKeyedFastElement
+class HStoreKeyed
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
- HStoreKeyedFastElement(HValue* obj, HValue* key, HValue* val,
- ElementsKind elements_kind = FAST_ELEMENTS)
- : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
+ HStoreKeyed(HValue* obj, HValue* key, HValue* val,
+ ElementsKind elements_kind)
+ : elements_kind_(elements_kind),
+ index_offset_(0),
+ is_dehoisted_(false),
+ new_space_dominator_(NULL) {
SetOperandAt(0, obj);
SetOperandAt(1, key);
SetOperandAt(2, val);
- SetGVNFlag(kChangesArrayElements);
- }
-
- virtual Representation RequiredInputRepresentation(int index) {
- // The key is supposed to be Integer32.
- return index == 1
- ? Representation::Integer32()
- : Representation::Tagged();
- }
- HValue* object() { return OperandAt(0); }
- HValue* key() { return OperandAt(1); }
- HValue* value() { return OperandAt(2); }
- bool value_is_smi() {
- return IsFastSmiElementsKind(elements_kind_);
- }
- uint32_t index_offset() { return index_offset_; }
- void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
- HValue* GetKey() { return key(); }
- void SetKey(HValue* key) { SetOperandAt(1, key); }
- bool IsDehoisted() { return is_dehoisted_; }
- void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
-
- bool NeedsWriteBarrier() {
- if (value_is_smi()) {
- return false;
+ if (IsFastObjectElementsKind(elements_kind)) {
+ SetFlag(kTrackSideEffectDominators);
+ SetGVNFlag(kDependsOnNewSpacePromotion);
+ }
+ if (is_external()) {
+ SetGVNFlag(kChangesSpecializedArrayElements);
+ } else if (IsFastDoubleElementsKind(elements_kind)) {
+ SetGVNFlag(kChangesDoubleArrayElements);
+ SetFlag(kDeoptimizeOnUndefined);
} else {
- return StoringValueNeedsWriteBarrier(value());
+ SetGVNFlag(kChangesArrayElements);
}
- }
- virtual void PrintDataTo(StringStream* stream);
+ // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
+ if (elements_kind >= EXTERNAL_BYTE_ELEMENTS &&
+ elements_kind <= EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ SetFlag(kTruncatingToInt32);
+ }
+ }
- DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement)
+ virtual Representation RequiredInputRepresentation(int index) {
+ // kind_fast: tagged[int32] = tagged
+ // kind_double: tagged[int32] = double
+ // kind_external: external[int32] = (double | int32)
+ if (index == 0) {
+ return is_external() ? Representation::External()
+ : Representation::Tagged();
+ } else if (index == 1) {
+ return ArrayInstructionInterface::KeyedAccessIndexRequirement(
+ OperandAt(1)->representation());
+ }
- private:
- ElementsKind elements_kind_;
- uint32_t index_offset_;
- bool is_dehoisted_;
-};
+ ASSERT_EQ(index, 2);
+ if (IsDoubleOrFloatElementsKind(elements_kind())) {
+ return Representation::Double();
+ }
+ return is_external() ? Representation::Integer32()
+ : Representation::Tagged();
+ }
-class HStoreKeyedFastDoubleElement
- : public HTemplateInstruction<3>, public ArrayInstructionInterface {
- public:
- HStoreKeyedFastDoubleElement(HValue* elements,
- HValue* key,
- HValue* val)
- : index_offset_(0), is_dehoisted_(false) {
- SetOperandAt(0, elements);
- SetOperandAt(1, key);
- SetOperandAt(2, val);
- SetFlag(kDeoptimizeOnUndefined);
- SetGVNFlag(kChangesDoubleArrayElements);
+ bool is_external() const {
+ return IsExternalArrayElementsKind(elements_kind());
}
- virtual Representation RequiredInputRepresentation(int index) {
- if (index == 1) {
- return Representation::Integer32();
- } else if (index == 2) {
+ virtual Representation observed_input_representation(int index) {
+ if (index < 2) return RequiredInputRepresentation(index);
+ if (IsDoubleOrFloatElementsKind(elements_kind())) {
return Representation::Double();
- } else {
- return Representation::Tagged();
}
+ if (is_external()) {
+ return Representation::Integer32();
+ }
+ // For fast object elements kinds, don't assume anything.
+ return Representation::None();
}
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
+ bool value_is_smi() const {
+ return IsFastSmiElementsKind(elements_kind_);
+ }
+ ElementsKind elements_kind() const { return elements_kind_; }
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
HValue* GetKey() { return key(); }
@@ -4653,70 +5688,33 @@ class HStoreKeyedFastDoubleElement
bool IsDehoisted() { return is_dehoisted_; }
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
- bool NeedsWriteBarrier() {
- return StoringValueNeedsWriteBarrier(value());
- }
-
- bool NeedsCanonicalization();
-
- virtual void PrintDataTo(StringStream* stream);
-
- DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement)
-
- private:
- uint32_t index_offset_;
- bool is_dehoisted_;
-};
-
-
-class HStoreKeyedSpecializedArrayElement
- : public HTemplateInstruction<3>, public ArrayInstructionInterface {
- public:
- HStoreKeyedSpecializedArrayElement(HValue* external_elements,
- HValue* key,
- HValue* val,
- ElementsKind elements_kind)
- : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
- SetGVNFlag(kChangesSpecializedArrayElements);
- SetOperandAt(0, external_elements);
- SetOperandAt(1, key);
- SetOperandAt(2, val);
+ virtual void SetSideEffectDominator(GVNFlag side_effect, HValue* dominator) {
+ ASSERT(side_effect == kChangesNewSpacePromotion);
+ new_space_dominator_ = dominator;
}
- virtual void PrintDataTo(StringStream* stream);
+ HValue* new_space_dominator() const { return new_space_dominator_; }
- virtual Representation RequiredInputRepresentation(int index) {
- if (index == 0) {
- return Representation::External();
+ bool NeedsWriteBarrier() {
+ if (value_is_smi()) {
+ return false;
} else {
- bool float_or_double_elements =
- elements_kind() == EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind() == EXTERNAL_DOUBLE_ELEMENTS;
- if (index == 2 && float_or_double_elements) {
- return Representation::Double();
- } else {
- return Representation::Integer32();
- }
+ return StoringValueNeedsWriteBarrier(value()) &&
+ ReceiverObjectNeedsWriteBarrier(elements(), new_space_dominator());
}
}
- HValue* external_pointer() { return OperandAt(0); }
- HValue* key() { return OperandAt(1); }
- HValue* value() { return OperandAt(2); }
- ElementsKind elements_kind() const { return elements_kind_; }
- uint32_t index_offset() { return index_offset_; }
- void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
- HValue* GetKey() { return key(); }
- void SetKey(HValue* key) { SetOperandAt(1, key); }
- bool IsDehoisted() { return is_dehoisted_; }
- void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
+ bool NeedsCanonicalization();
+
+ virtual void PrintDataTo(StringStream* stream);
- DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement)
+ DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
private:
ElementsKind elements_kind_;
uint32_t index_offset_;
bool is_dehoisted_;
+ HValue* new_space_dominator_;
};
@@ -4742,6 +5740,7 @@ class HStoreKeyedGeneric: public HTemplateInstruction<4> {
StrictModeFlag strict_mode_flag() { return strict_mode_flag_; }
virtual Representation RequiredInputRepresentation(int index) {
+ // tagged[tagged] = tagged
return Representation::Tagged();
}
@@ -4754,14 +5753,18 @@ class HStoreKeyedGeneric: public HTemplateInstruction<4> {
};
-class HTransitionElementsKind: public HTemplateInstruction<1> {
+class HTransitionElementsKind: public HTemplateInstruction<2> {
public:
- HTransitionElementsKind(HValue* object,
+ HTransitionElementsKind(HValue* context,
+ HValue* object,
Handle<Map> original_map,
Handle<Map> transitioned_map)
: original_map_(original_map),
- transitioned_map_(transitioned_map) {
+ transitioned_map_(transitioned_map),
+ from_kind_(original_map->elements_kind()),
+ to_kind_(transitioned_map->elements_kind()) {
SetOperandAt(0, object);
+ SetOperandAt(1, context);
SetFlag(kUseGVN);
SetGVNFlag(kChangesElementsKind);
if (original_map->has_fast_double_elements()) {
@@ -4780,8 +5783,11 @@ class HTransitionElementsKind: public HTemplateInstruction<1> {
}
HValue* object() { return OperandAt(0); }
+ HValue* context() { return OperandAt(1); }
Handle<Map> original_map() { return original_map_; }
Handle<Map> transitioned_map() { return transitioned_map_; }
+ ElementsKind from_kind() { return from_kind_; }
+ ElementsKind to_kind() { return to_kind_; }
virtual void PrintDataTo(StringStream* stream);
@@ -4797,18 +5803,17 @@ class HTransitionElementsKind: public HTemplateInstruction<1> {
private:
Handle<Map> original_map_;
Handle<Map> transitioned_map_;
+ ElementsKind from_kind_;
+ ElementsKind to_kind_;
};
class HStringAdd: public HBinaryOperation {
public:
- HStringAdd(HValue* context, HValue* left, HValue* right)
- : HBinaryOperation(context, left, right) {
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- SetGVNFlag(kDependsOnMaps);
- SetGVNFlag(kChangesNewSpacePromotion);
- }
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
@@ -4823,8 +5828,17 @@ class HStringAdd: public HBinaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ HStringAdd(HValue* context, HValue* left, HValue* right)
+ : HBinaryOperation(context, left, right) {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ SetGVNFlag(kDependsOnMaps);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+
// TODO(svenpanne) Might be safe, but leave it out until we know for sure.
- // private:
// virtual bool IsDeletable() const { return true; }
};
@@ -4869,13 +5883,9 @@ class HStringCharCodeAt: public HTemplateInstruction<3> {
class HStringCharFromCode: public HTemplateInstruction<2> {
public:
- HStringCharFromCode(HValue* context, HValue* char_code) {
- SetOperandAt(0, context);
- SetOperandAt(1, char_code);
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- SetGVNFlag(kChangesNewSpacePromotion);
- }
+ static HInstruction* New(Zone* zone,
+ HValue* context,
+ HValue* char_code);
virtual Representation RequiredInputRepresentation(int index) {
return index == 0
@@ -4891,19 +5901,23 @@ class HStringCharFromCode: public HTemplateInstruction<2> {
DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
+ private:
+ HStringCharFromCode(HValue* context, HValue* char_code) {
+ SetOperandAt(0, context);
+ SetOperandAt(1, char_code);
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+
// TODO(svenpanne) Might be safe, but leave it out until we know for sure.
- // private:
- // virtual bool IsDeletable() const { return true; }
+ // virtual bool IsDeletable() const { return true; }
};
class HStringLength: public HUnaryOperation {
public:
- explicit HStringLength(HValue* string) : HUnaryOperation(string) {
- set_representation(Representation::Tagged());
- SetFlag(kUseGVN);
- SetGVNFlag(kDependsOnMaps);
- }
+ static HInstruction* New(Zone* zone, HValue* string);
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
@@ -4924,56 +5938,42 @@ class HStringLength: public HUnaryOperation {
}
private:
- virtual bool IsDeletable() const { return true; }
-};
-
-
-class HAllocateObject: public HTemplateInstruction<1> {
- public:
- HAllocateObject(HValue* context, Handle<JSFunction> constructor)
- : constructor_(constructor) {
- SetOperandAt(0, context);
+ explicit HStringLength(HValue* string) : HUnaryOperation(string) {
set_representation(Representation::Tagged());
- SetGVNFlag(kChangesNewSpacePromotion);
- }
-
- // Maximum instance size for which allocations will be inlined.
- static const int kMaxSize = 64 * kPointerSize;
-
- HValue* context() { return OperandAt(0); }
- Handle<JSFunction> constructor() { return constructor_; }
-
- virtual Representation RequiredInputRepresentation(int index) {
- return Representation::Tagged();
+ SetFlag(kUseGVN);
+ SetGVNFlag(kDependsOnMaps);
}
- virtual HType CalculateInferredType();
-
- DECLARE_CONCRETE_INSTRUCTION(AllocateObject)
-
- private:
- // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
- // virtual bool IsDeletable() const { return true; }
- Handle<JSFunction> constructor_;
+ virtual bool IsDeletable() const { return true; }
};
template <int V>
class HMaterializedLiteral: public HTemplateInstruction<V> {
public:
+ HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode)
+ : literal_index_(index), depth_(depth), allocation_site_mode_(mode) {
+ this->set_representation(Representation::Tagged());
+ }
+
HMaterializedLiteral<V>(int index, int depth)
- : literal_index_(index), depth_(depth) {
+ : literal_index_(index), depth_(depth),
+ allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) {
this->set_representation(Representation::Tagged());
}
int literal_index() const { return literal_index_; }
int depth() const { return depth_; }
+ AllocationSiteMode allocation_site_mode() const {
+ return allocation_site_mode_;
+ }
private:
virtual bool IsDeletable() const { return true; }
int literal_index_;
int depth_;
+ AllocationSiteMode allocation_site_mode_;
};
@@ -4983,8 +5983,9 @@ class HFastLiteral: public HMaterializedLiteral<1> {
Handle<JSObject> boilerplate,
int total_size,
int literal_index,
- int depth)
- : HMaterializedLiteral<1>(literal_index, depth),
+ int depth,
+ AllocationSiteMode mode)
+ : HMaterializedLiteral<1>(literal_index, depth, mode),
boilerplate_(boilerplate),
total_size_(total_size) {
SetOperandAt(0, context);
@@ -4999,10 +6000,12 @@ class HFastLiteral: public HMaterializedLiteral<1> {
HValue* context() { return OperandAt(0); }
Handle<JSObject> boilerplate() const { return boilerplate_; }
int total_size() const { return total_size_; }
-
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
+ virtual Handle<Map> GetMonomorphicJSObjectMap() {
+ return Handle<Map>(boilerplate()->map());
+ }
virtual HType CalculateInferredType();
DECLARE_CONCRETE_INSTRUCTION(FastLiteral)
@@ -5019,8 +6022,9 @@ class HArrayLiteral: public HMaterializedLiteral<1> {
Handle<HeapObject> boilerplate_object,
int length,
int literal_index,
- int depth)
- : HMaterializedLiteral<1>(literal_index, depth),
+ int depth,
+ AllocationSiteMode mode)
+ : HMaterializedLiteral<1>(literal_index, depth, mode),
length_(length),
boilerplate_object_(boilerplate_object) {
SetOperandAt(0, context);
@@ -5036,7 +6040,6 @@ class HArrayLiteral: public HMaterializedLiteral<1> {
}
Handle<HeapObject> boilerplate_object() const { return boilerplate_object_; }
int length() const { return length_; }
-
bool IsCopyOnWrite() const;
virtual Representation RequiredInputRepresentation(int index) {
@@ -5165,7 +6168,6 @@ class HTypeof: public HTemplateInstruction<2> {
HValue* context() { return OperandAt(0); }
HValue* value() { return OperandAt(1); }
- virtual HValue* Canonicalize();
virtual void PrintDataTo(StringStream* stream);
virtual Representation RequiredInputRepresentation(int index) {
@@ -5179,6 +6181,22 @@ class HTypeof: public HTemplateInstruction<2> {
};
+class HTrapAllocationMemento : public HTemplateInstruction<1> {
+ public:
+ explicit HTrapAllocationMemento(HValue* obj) {
+ SetOperandAt(0, obj);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ HValue* object() { return OperandAt(0); }
+
+ DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento)
+};
+
+
class HToFastProperties: public HUnaryOperation {
public:
explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
@@ -5237,6 +6255,33 @@ class HDateField: public HUnaryOperation {
};
+class HSeqStringSetChar: public HTemplateInstruction<3> {
+ public:
+ HSeqStringSetChar(String::Encoding encoding,
+ HValue* string,
+ HValue* index,
+ HValue* value) : encoding_(encoding) {
+ SetOperandAt(0, string);
+ SetOperandAt(1, index);
+ SetOperandAt(2, value);
+ }
+
+ String::Encoding encoding() { return encoding_; }
+ HValue* string() { return OperandAt(0); }
+ HValue* index() { return OperandAt(1); }
+ HValue* value() { return OperandAt(2); }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar)
+
+ private:
+ String::Encoding encoding_;
+};
+
+
class HDeleteProperty: public HBinaryOperation {
public:
HDeleteProperty(HValue* context, HValue* obj, HValue* key)