| Index: src/hydrogen-instructions.h
|
| diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
|
| index 3fae45bcb7663b8b8e50f86b9852eea2a65b38fd..eac5173f7d00748bec37cba8a7bb68990113342c 100644
|
| --- a/src/hydrogen-instructions.h
|
| +++ b/src/hydrogen-instructions.h
|
| @@ -72,6 +72,7 @@ class LChunkBuilder;
|
| V(ArgumentsLength) \
|
| V(ArgumentsObject) \
|
| V(Bitwise) \
|
| + V(BitNot) \
|
| V(BlockEntry) \
|
| V(BoundsCheck) \
|
| V(BoundsCheckBaseIndexInformation) \
|
| @@ -92,6 +93,7 @@ class LChunkBuilder;
|
| V(CheckInstanceType) \
|
| V(CheckMaps) \
|
| V(CheckMapValue) \
|
| + V(CheckPrototypeMaps) \
|
| V(CheckSmi) \
|
| V(ClampToUint8) \
|
| V(ClassOfTestAndBranch) \
|
| @@ -120,6 +122,7 @@ class LChunkBuilder;
|
| V(Goto) \
|
| V(HasCachedArrayIndexAndBranch) \
|
| V(HasInstanceTypeAndBranch) \
|
| + V(InductionVariableAnnotation) \
|
| V(InnerAllocatedObject) \
|
| V(InstanceOf) \
|
| V(InstanceOfKnownGlobal) \
|
| @@ -148,6 +151,7 @@ class LChunkBuilder;
|
| V(MathMinMax) \
|
| V(Mod) \
|
| V(Mul) \
|
| + V(NumericConstraint) \
|
| V(OsrEntry) \
|
| V(OuterContext) \
|
| V(Parameter) \
|
| @@ -538,6 +542,158 @@ enum GVNFlag {
|
| };
|
|
|
|
|
| +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) {}
|
| @@ -583,6 +739,46 @@ class DecompositionResult BASE_EMBEDDED {
|
| };
|
|
|
|
|
| +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;
|
|
|
|
|
| @@ -620,6 +816,12 @@ class HValue: public ZoneObject {
|
| // HGraph::ComputeSafeUint32Operations is responsible for setting this
|
| // flag.
|
| 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,
|
| kHasNoObservableSideEffects,
|
| // Indicates the instruction is live during dead code elimination.
|
| kIsLive,
|
| @@ -757,8 +959,8 @@ class HValue: public ZoneObject {
|
| return RedefinedOperandIndex() != kNoRedefinedOperand;
|
| }
|
| HValue* RedefinedOperand() {
|
| - int index = RedefinedOperandIndex();
|
| - return index == kNoRedefinedOperand ? NULL : OperandAt(index);
|
| + return IsInformativeDefinition() ? OperandAt(RedefinedOperandIndex())
|
| + : NULL;
|
| }
|
|
|
| // A purely informative definition is an idef that will not emit code and
|
| @@ -769,8 +971,17 @@ class HValue: public ZoneObject {
|
| // This method must always return the original HValue SSA definition
|
| // (regardless of any iDef of this value).
|
| HValue* ActualValue() {
|
| - int index = RedefinedOperandIndex();
|
| - return index == kNoRedefinedOperand ? this : OperandAt(index);
|
| + return IsInformativeDefinition() ? RedefinedOperand()->ActualValue()
|
| + : this;
|
| + }
|
| +
|
| + virtual void AddInformativeDefinitions() {}
|
| +
|
| + void UpdateRedefinedUsesWhileSettingUpInformativeDefinitions() {
|
| + UpdateRedefinedUsesInner<TestDominanceUsingProcessedFlag>();
|
| + }
|
| + void UpdateRedefinedUses() {
|
| + UpdateRedefinedUsesInner<Dominates>();
|
| }
|
|
|
| bool IsInteger32Constant();
|
| @@ -921,6 +1132,12 @@ 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);
|
| @@ -942,6 +1159,17 @@ class HValue: public ZoneObject {
|
| }
|
|
|
| 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) {
|
| @@ -975,6 +1203,47 @@ class HValue: public ZoneObject {
|
| 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.
|
| @@ -1245,6 +1514,52 @@ class HDummyUse: public HTemplateInstruction<1> {
|
| };
|
|
|
|
|
| +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_;
|
| +};
|
| +
|
| +
|
| class HDeoptimize: public HTemplateInstruction<0> {
|
| public:
|
| DECLARE_INSTRUCTION_FACTORY_P1(HDeoptimize, Deoptimizer::BailoutType);
|
| @@ -2391,6 +2706,37 @@ class HElementsKind: public HUnaryOperation {
|
| };
|
|
|
|
|
| +class HBitNot: public HUnaryOperation {
|
| + public:
|
| + DECLARE_INSTRUCTION_FACTORY_P1(HBitNot, HValue*);
|
| +
|
| + virtual Representation RequiredInputRepresentation(int index) {
|
| + return Representation::Integer32();
|
| + }
|
| + virtual Representation observed_input_representation(int index) {
|
| + return Representation::Integer32();
|
| + }
|
| +
|
| + virtual HValue* Canonicalize();
|
| +
|
| + DECLARE_CONCRETE_INSTRUCTION(BitNot)
|
| +
|
| + protected:
|
| + virtual bool DataEquals(HValue* other) { return true; }
|
| +
|
| + private:
|
| + explicit HBitNot(HValue* value)
|
| + : HUnaryOperation(value, HType::TaggedNumber()) {
|
| + set_representation(Representation::Integer32());
|
| + SetFlag(kUseGVN);
|
| + SetFlag(kTruncatingToInt32);
|
| + SetFlag(kAllowUndefinedAsNaN);
|
| + }
|
| +
|
| + virtual bool IsDeletable() const { return true; }
|
| +};
|
| +
|
| +
|
| class HUnaryMathOperation: public HTemplateInstruction<2> {
|
| public:
|
| static HInstruction* New(Zone* zone,
|
| @@ -2532,7 +2878,6 @@ class HCheckMaps: public HTemplateInstruction<2> {
|
| HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck);
|
| for (int i = 0; i < maps->length(); i++) {
|
| check_map->map_set_.Add(maps->at(i), zone);
|
| - check_map->has_migration_target_ |= maps->at(i)->is_migration_target();
|
| }
|
| check_map->map_set_.Sort();
|
| return check_map;
|
| @@ -2551,10 +2896,6 @@ class HCheckMaps: public HTemplateInstruction<2> {
|
| HValue* value() { return OperandAt(0); }
|
| SmallMapList* map_set() { return &map_set_; }
|
|
|
| - bool has_migration_target() {
|
| - return has_migration_target_;
|
| - }
|
| -
|
| virtual void FinalizeUniqueValueId();
|
|
|
| DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
|
| @@ -2579,7 +2920,7 @@ class HCheckMaps: public HTemplateInstruction<2> {
|
| // Clients should use one of the static New* methods above.
|
| HCheckMaps(HValue* value, Zone *zone, HValue* typecheck)
|
| : HTemplateInstruction<2>(value->type()),
|
| - omit_(false), has_migration_target_(false), map_unique_ids_(0, zone) {
|
| + omit_(false), map_unique_ids_(0, zone) {
|
| SetOperandAt(0, value);
|
| // Use the object value for the dependency if NULL is passed.
|
| // TODO(titzer): do GVN flags already express this dependency?
|
| @@ -2601,7 +2942,6 @@ class HCheckMaps: public HTemplateInstruction<2> {
|
| }
|
|
|
| bool omit_;
|
| - bool has_migration_target_;
|
| SmallMapList map_set_;
|
| ZoneList<UniqueValueId> map_unique_ids_;
|
| };
|
| @@ -2786,6 +3126,87 @@ class HCheckHeapObject: public HUnaryOperation {
|
| };
|
|
|
|
|
| +class HCheckPrototypeMaps: public HTemplateInstruction<0> {
|
| + public:
|
| + static HCheckPrototypeMaps* New(Zone* zone,
|
| + HValue* context,
|
| + Handle<JSObject> prototype,
|
| + Handle<JSObject> holder,
|
| + CompilationInfo* info) {
|
| + return new(zone) HCheckPrototypeMaps(prototype, holder, zone, info);
|
| + }
|
| +
|
| + ZoneList<Handle<JSObject> >* prototypes() { return &prototypes_; }
|
| +
|
| + ZoneList<Handle<Map> >* maps() { return &maps_; }
|
| +
|
| + DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps)
|
| +
|
| + virtual Representation RequiredInputRepresentation(int index) {
|
| + return Representation::None();
|
| + }
|
| +
|
| + virtual void PrintDataTo(StringStream* stream);
|
| +
|
| + virtual intptr_t Hashcode() {
|
| + return first_prototype_unique_id_.Hashcode() * 17 +
|
| + last_prototype_unique_id_.Hashcode();
|
| + }
|
| +
|
| + virtual void FinalizeUniqueValueId() {
|
| + first_prototype_unique_id_ = UniqueValueId(prototypes_.first());
|
| + last_prototype_unique_id_ = UniqueValueId(prototypes_.last());
|
| + }
|
| +
|
| + bool CanOmitPrototypeChecks() { return can_omit_prototype_maps_; }
|
| +
|
| + protected:
|
| + virtual bool DataEquals(HValue* other) {
|
| + HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other);
|
| + return first_prototype_unique_id_ == b->first_prototype_unique_id_ &&
|
| + last_prototype_unique_id_ == b->last_prototype_unique_id_;
|
| + }
|
| +
|
| + private:
|
| + HCheckPrototypeMaps(Handle<JSObject> prototype,
|
| + Handle<JSObject> holder,
|
| + Zone* zone,
|
| + CompilationInfo* info)
|
| + : prototypes_(2, zone),
|
| + maps_(2, zone),
|
| + first_prototype_unique_id_(),
|
| + last_prototype_unique_id_(),
|
| + can_omit_prototype_maps_(true) {
|
| + 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);
|
| + Handle<Map> map(prototype->map());
|
| + maps_.Add(map, zone);
|
| + can_omit_prototype_maps_ &= map->CanOmitPrototypeChecks();
|
| + if (prototype.is_identical_to(holder)) break;
|
| + prototype = Handle<JSObject>(JSObject::cast(prototype->GetPrototype()));
|
| + }
|
| + if (can_omit_prototype_maps_) {
|
| + // Mark in-flight compilation as dependent on those maps.
|
| + for (int i = 0; i < maps()->length(); i++) {
|
| + Handle<Map> map = maps()->at(i);
|
| + map->AddDependentCompilationInfo(DependentCode::kPrototypeCheckGroup,
|
| + info);
|
| + }
|
| + }
|
| + }
|
| +
|
| + ZoneList<Handle<JSObject> > prototypes_;
|
| + ZoneList<Handle<Map> > maps_;
|
| + UniqueValueId first_prototype_unique_id_;
|
| + UniqueValueId last_prototype_unique_id_;
|
| + bool can_omit_prototype_maps_;
|
| +};
|
| +
|
| +
|
| class InductionVariableData;
|
|
|
|
|
| @@ -3059,6 +3480,8 @@ class HPhi: public HValue {
|
| induction_variable_data_ = InductionVariableData::ExaminePhi(this);
|
| }
|
|
|
| + virtual void AddInformativeDefinitions();
|
| +
|
| virtual void PrintTo(StringStream* stream);
|
|
|
| #ifdef DEBUG
|
| @@ -3109,6 +3532,11 @@ class HPhi: public HValue {
|
| inputs_[index] = value;
|
| }
|
|
|
| + virtual bool IsRelationTrueInternal(NumericRelation relation,
|
| + HValue* other,
|
| + int offset = 0,
|
| + int scale = 0);
|
| +
|
| private:
|
| ZoneList<HValue*> inputs_;
|
| int merged_index_;
|
| @@ -3123,6 +3551,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:
|
| static HArgumentsObject* New(Zone* zone,
|
| @@ -3212,9 +3687,6 @@ class HConstant: public HTemplateInstruction<0> {
|
| }
|
| return false;
|
| }
|
| - if (has_external_reference_value_) {
|
| - return false;
|
| - }
|
|
|
| ASSERT(!handle_.is_null());
|
| Heap* heap = isolate()->heap();
|
| @@ -3643,6 +4115,12 @@ class HBoundsCheck: public HTemplateInstruction<2> {
|
| 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() {
|
| @@ -3666,6 +4144,11 @@ class HBoundsCheck: public HTemplateInstruction<2> {
|
| return representation();
|
| }
|
|
|
| + virtual bool IsRelationTrueInternal(NumericRelation relation,
|
| + HValue* related_value,
|
| + int offset = 0,
|
| + int scale = 0);
|
| +
|
| virtual void PrintDataTo(StringStream* stream);
|
| virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
|
|
|
| @@ -3676,17 +4159,25 @@ class HBoundsCheck: public HTemplateInstruction<2> {
|
|
|
| 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);
|
| bool skip_check_;
|
| HValue* base_;
|
| int offset_;
|
| int scale_;
|
| + RangeGuaranteeDirection responsibility_direction_;
|
| bool allow_equality_;
|
|
|
| private:
|
| @@ -3697,6 +4188,7 @@ class HBoundsCheck: public HTemplateInstruction<2> {
|
| HBoundsCheck(HValue* index, HValue* length)
|
| : skip_check_(false),
|
| base_(NULL), offset_(0), scale_(0),
|
| + responsibility_direction_(DIRECTION_NONE),
|
| allow_equality_(false) {
|
| SetOperandAt(0, index);
|
| SetOperandAt(1, length);
|
| @@ -3731,10 +4223,22 @@ class HBoundsCheckBaseIndexInformation: public HTemplateInstruction<2> {
|
| 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);
|
| + }
|
| };
|
|
|
|
|
| @@ -3907,6 +4411,8 @@ class HCompareNumericAndBranch: public HTemplateControlInstruction<2, 2> {
|
| }
|
| virtual void PrintDataTo(StringStream* stream);
|
|
|
| + virtual void AddInformativeDefinitions();
|
| +
|
| DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
|
|
|
| private:
|
| @@ -5866,7 +6372,7 @@ class HLoadKeyedGeneric: public HTemplateInstruction<3> {
|
| };
|
|
|
|
|
| -class HStoreNamedField: public HTemplateInstruction<3> {
|
| +class HStoreNamedField: public HTemplateInstruction<2> {
|
| public:
|
| DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
|
| HObjectAccess, HValue*);
|
| @@ -5898,35 +6404,24 @@ class HStoreNamedField: public HTemplateInstruction<3> {
|
| return write_barrier_mode_ == SKIP_WRITE_BARRIER;
|
| }
|
|
|
| - HValue* object() const { return OperandAt(0); }
|
| - HValue* value() const { return OperandAt(1); }
|
| - HValue* transition() const { return OperandAt(2); }
|
| + HValue* object() { return OperandAt(0); }
|
| + HValue* value() { return OperandAt(1); }
|
|
|
| HObjectAccess access() const { return access_; }
|
| - HValue* new_space_dominator() const { return new_space_dominator_; }
|
| - bool has_transition() const { return has_transition_; }
|
| -
|
| - Handle<Map> transition_map() const {
|
| - if (has_transition()) {
|
| - return Handle<Map>::cast(HConstant::cast(transition())->handle());
|
| - } else {
|
| - return Handle<Map>();
|
| - }
|
| - }
|
| -
|
| - void SetTransition(HConstant* map_constant, CompilationInfo* info) {
|
| - ASSERT(!has_transition()); // Only set once.
|
| - Handle<Map> map = Handle<Map>::cast(map_constant->handle());
|
| + Handle<Map> transition() const { return transition_; }
|
| + UniqueValueId transition_unique_id() const { return transition_unique_id_; }
|
| + void SetTransition(Handle<Map> map, CompilationInfo* info) {
|
| + ASSERT(transition_.is_null()); // Only set once.
|
| if (map->CanBeDeprecated()) {
|
| map->AddDependentCompilationInfo(DependentCode::kTransitionGroup, info);
|
| }
|
| - SetOperandAt(2, map_constant);
|
| - has_transition_ = true;
|
| + transition_ = map;
|
| }
|
| + HValue* new_space_dominator() const { return new_space_dominator_; }
|
|
|
| bool NeedsWriteBarrier() {
|
| ASSERT(!(FLAG_track_double_fields && field_representation().IsDouble()) ||
|
| - !has_transition());
|
| + transition_.is_null());
|
| if (IsSkipWriteBarrier()) return false;
|
| if (field_representation().IsDouble()) return false;
|
| if (field_representation().IsSmi()) return false;
|
| @@ -5941,6 +6436,10 @@ class HStoreNamedField: public HTemplateInstruction<3> {
|
| return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
|
| }
|
|
|
| + virtual void FinalizeUniqueValueId() {
|
| + transition_unique_id_ = UniqueValueId(transition_);
|
| + }
|
| +
|
| Representation field_representation() const {
|
| return access_.representation();
|
| }
|
| @@ -5950,19 +6449,20 @@ class HStoreNamedField: public HTemplateInstruction<3> {
|
| HObjectAccess access,
|
| HValue* val)
|
| : access_(access),
|
| + transition_(),
|
| + transition_unique_id_(),
|
| new_space_dominator_(NULL),
|
| - write_barrier_mode_(UPDATE_WRITE_BARRIER),
|
| - has_transition_(false) {
|
| + write_barrier_mode_(UPDATE_WRITE_BARRIER) {
|
| SetOperandAt(0, obj);
|
| SetOperandAt(1, val);
|
| - SetOperandAt(2, obj);
|
| access.SetGVNFlags(this, true);
|
| }
|
|
|
| HObjectAccess access_;
|
| + Handle<Map> transition_;
|
| + UniqueValueId transition_unique_id_;
|
| HValue* new_space_dominator_;
|
| - WriteBarrierMode write_barrier_mode_ : 1;
|
| - bool has_transition_ : 1;
|
| + WriteBarrierMode write_barrier_mode_;
|
| };
|
|
|
|
|
|
|