diff options
Diffstat (limited to 'deps/v8/src/hydrogen-instructions.h')
-rw-r--r-- | deps/v8/src/hydrogen-instructions.h | 2233 |
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) |