diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 37683bde9850..fe08fb0ab127 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -281,8 +281,7 @@ SymbolicBound::print(Sprinter &sp) const void Range::print(Sprinter &sp) const { - JS_ASSERT_IF(!hasInt32LowerBound_, lower_ == JSVAL_INT_MIN); - JS_ASSERT_IF(!hasInt32UpperBound_, upper_ == JSVAL_INT_MAX); + assertInvariants(); // Floating-point or Integer subset. if (canHaveFractionalPart_) @@ -789,6 +788,7 @@ Range::update(const Range *other) hasInt32UpperBound_ = other->hasInt32UpperBound_; canHaveFractionalPart_ = other->canHaveFractionalPart_; max_exponent_ = other->max_exponent_; + assertInvariants(); } return changed; diff --git a/js/src/jit/RangeAnalysis.h b/js/src/jit/RangeAnalysis.h index 68302b52dcc2..b348b798cce7 100644 --- a/js/src/jit/RangeAnalysis.h +++ b/js/src/jit/RangeAnalysis.h @@ -173,6 +173,27 @@ class Range : public TempObject { const SymbolicBound *symbolicLower_; const SymbolicBound *symbolicUpper_; + // This function simply makes several JS_ASSERTs to verify the internal + // consistency of this range. + void assertInvariants() const { + JS_ASSERT(lower_ <= upper_); + JS_ASSERT_IF(!hasInt32LowerBound_, lower_ == JSVAL_INT_MIN); + JS_ASSERT_IF(!hasInt32UpperBound_, upper_ == JSVAL_INT_MAX); + JS_ASSERT_IF(!hasInt32LowerBound_ || !hasInt32UpperBound_, max_exponent_ >= MaxInt32Exponent); + JS_ASSERT(max_exponent_ <= MaxFiniteExponent || + max_exponent_ == IncludesInfinity || + max_exponent_ == IncludesInfinityAndNaN); + JS_ASSERT(max_exponent_ >= mozilla::FloorLog2(mozilla::Abs(upper_))); + JS_ASSERT(max_exponent_ >= mozilla::FloorLog2(mozilla::Abs(lower_))); + + // The following are essentially static assertions, but FloorLog2 isn't + // trivially suitable for constexpr :(. + JS_ASSERT(mozilla::FloorLog2(JSVAL_INT_MIN) == MaxInt32Exponent); + JS_ASSERT(mozilla::FloorLog2(JSVAL_INT_MAX) == 30); + JS_ASSERT(mozilla::FloorLog2(UINT32_MAX) == MaxUInt32Exponent); + JS_ASSERT(mozilla::FloorLog2(0) == 0); + } + // Set the lower_ and hasInt32LowerBound_ values. void setLowerInit(int64_t x) { if (x > JSVAL_INT_MAX) { @@ -218,18 +239,24 @@ class Range : public TempObject { // any other field, update that field to the stronger value. The range must // be completely valid before and it is guaranteed to be kept valid. void optimize() { + assertInvariants(); + if (hasInt32Bounds()) { // Examine lower() and upper(), and if they imply a better exponent // bound than max_exponent_, set that value as the new // max_exponent_. uint16_t newExponent = exponentImpliedByInt32Bounds(); - if (newExponent < max_exponent_) + if (newExponent < max_exponent_) { max_exponent_ = newExponent; + assertInvariants(); + } // If we have a completely precise range, the value is an integer, // since we can only represent integers. - if (canHaveFractionalPart_ && lower_ == upper_) + if (canHaveFractionalPart_ && lower_ == upper_) { canHaveFractionalPart_ = false; + assertInvariants(); + } } } @@ -277,8 +304,7 @@ class Range : public TempObject { symbolicLower_(nullptr), symbolicUpper_(nullptr) { - JS_ASSERT_IF(!hasInt32LowerBound_, lower_ == JSVAL_INT_MIN); - JS_ASSERT_IF(!hasInt32UpperBound_, upper_ == JSVAL_INT_MAX); + assertInvariants(); } Range(const MDefinition *def); @@ -420,18 +446,18 @@ class Range : public TempObject { // Set this range to have a lower bound not less than x. void refineLower(int32_t x) { + assertInvariants(); hasInt32LowerBound_ = true; lower_ = Max(lower_, x); optimize(); - JS_ASSERT_IF(!hasInt32LowerBound_, lower_ == JSVAL_INT_MIN); } // Set this range to have an upper bound not greater than x. void refineUpper(int32_t x) { + assertInvariants(); hasInt32UpperBound_ = true; upper_ = Min(upper_, x); optimize(); - JS_ASSERT_IF(!hasInt32UpperBound_, upper_ == JSVAL_INT_MAX); } void setInt32(int32_t l, int32_t h) { @@ -441,6 +467,7 @@ class Range : public TempObject { upper_ = h; canHaveFractionalPart_ = false; max_exponent_ = exponentImpliedByInt32Bounds(); + assertInvariants(); } void setUnknown() {