From 978fe70beb3d297e34037d3776b39e9018d52980 Mon Sep 17 00:00:00 2001 From: mvstanton Date: Thu, 6 Oct 2016 07:13:34 -0700 Subject: [PATCH] [Turbofan] Introduce OtherNumberConstant. With this CL, we devolve all Constants introduced as they are with an object handle into * Range - for integers * Nan * MinusZero * OtherNumberConstant - for doubles * HeapConstant We reduce the amount we have to inspect an object handle during optimization. Also, simplifications result. For example, you never have to check if a Range contains a HeapConstant. BUG= Review-Url: https://codereview.chromium.org/2381523002 Cr-Commit-Position: refs/heads/master@{#40041} --- src/compiler/js-builtin-reducer.cc | 4 +- src/compiler/js-create-lowering.cc | 9 +- src/compiler/js-typed-lowering.cc | 53 +++-- src/compiler/operation-typer.cc | 10 +- src/compiler/simplified-lowering.cc | 6 +- src/compiler/typed-optimization.cc | 21 +- src/compiler/typer.cc | 54 +++-- src/compiler/types.cc | 98 +++++--- src/compiler/types.h | 71 ++++-- test/cctest/test-types.cc | 217 +++++++++--------- test/cctest/types-fuzz.h | 38 ++- test/unittests/compiler/graph-unittest.cc | 2 +- .../compiler/js-create-lowering-unittest.cc | 2 +- .../compiler/typed-optimization-unittest.cc | 26 +-- test/unittests/compiler/typer-unittest.cc | 14 +- 15 files changed, 365 insertions(+), 260 deletions(-) diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc index 78c3286d05..4c15ee9078 100644 --- a/src/compiler/js-builtin-reducer.cc +++ b/src/compiler/js-builtin-reducer.cc @@ -330,9 +330,9 @@ bool HasInstanceTypeWitness(Node* receiver, Node* effect, for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) { Node* const map = NodeProperties::GetValueInput(dominator, i); Type* const map_type = NodeProperties::GetType(map); - if (!map_type->IsConstant()) return false; + if (!map_type->IsHeapConstant()) return false; Handle const map_value = - Handle::cast(map_type->AsConstant()->Value()); + Handle::cast(map_type->AsHeapConstant()->Value()); if (map_value->instance_type() != instance_type) return false; } return true; diff --git a/src/compiler/js-create-lowering.cc b/src/compiler/js-create-lowering.cc index b68bb7085d..073a088bcb 100644 --- a/src/compiler/js-create-lowering.cc +++ b/src/compiler/js-create-lowering.cc @@ -231,13 +231,12 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) { Type* const new_target_type = NodeProperties::GetType(new_target); Node* const effect = NodeProperties::GetEffectInput(node); // Extract constructor and original constructor function. - if (target_type->IsConstant() && - new_target_type->IsConstant() && - new_target_type->AsConstant()->Value()->IsJSFunction()) { + if (target_type->IsHeapConstant() && new_target_type->IsHeapConstant() && + new_target_type->AsHeapConstant()->Value()->IsJSFunction()) { Handle constructor = - Handle::cast(target_type->AsConstant()->Value()); + Handle::cast(target_type->AsHeapConstant()->Value()); Handle original_constructor = - Handle::cast(new_target_type->AsConstant()->Value()); + Handle::cast(new_target_type->AsHeapConstant()->Value()); DCHECK(constructor->IsConstructor()); DCHECK(original_constructor->IsConstructor()); diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index 31d4a3fc8c..c64c935938 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -82,16 +82,16 @@ class JSBinopReduction final { if (BothInputsAre(Type::String()) || ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) && BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) { - if (left_type()->IsConstant() && - left_type()->AsConstant()->Value()->IsString()) { + if (left_type()->IsHeapConstant() && + left_type()->AsHeapConstant()->Value()->IsString()) { Handle left_string = - Handle::cast(left_type()->AsConstant()->Value()); + Handle::cast(left_type()->AsHeapConstant()->Value()); if (left_string->length() >= ConsString::kMinLength) return true; } - if (right_type()->IsConstant() && - right_type()->AsConstant()->Value()->IsString()) { + if (right_type()->IsHeapConstant() && + right_type()->AsHeapConstant()->Value()->IsString()) { Handle right_string = - Handle::cast(right_type()->AsConstant()->Value()); + Handle::cast(right_type()->AsHeapConstant()->Value()); if (right_string->length() >= ConsString::kMinLength) return true; } } @@ -447,7 +447,6 @@ class JSBinopReduction final { // - immediately put in type bounds for all new nodes // - relax effects from generic but not-side-effecting operations - JSTypedLowering::JSTypedLowering(Editor* editor, CompilationDependencies* dependencies, Flags flags, JSGraph* jsgraph, Zone* zone) @@ -456,7 +455,7 @@ JSTypedLowering::JSTypedLowering(Editor* editor, flags_(flags), jsgraph_(jsgraph), the_hole_type_( - Type::Constant(factory()->the_hole_value(), graph()->zone())), + Type::HeapConstant(factory()->the_hole_value(), graph()->zone())), type_cache_(TypeCache::Get()) { for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { double min = kMinInt / (1 << k); @@ -598,9 +597,9 @@ Reduction JSTypedLowering::ReduceCreateConsString(Node* node) { // Determine the {first} length. Node* first_length = - first_type->IsConstant() + first_type->IsHeapConstant() ? jsgraph()->Constant( - Handle::cast(first_type->AsConstant()->Value()) + Handle::cast(first_type->AsHeapConstant()->Value()) ->length()) : effect = graph()->NewNode( simplified()->LoadField(AccessBuilder::ForStringLength()), @@ -608,9 +607,9 @@ Reduction JSTypedLowering::ReduceCreateConsString(Node* node) { // Determine the {second} length. Node* second_length = - second_type->IsConstant() + second_type->IsHeapConstant() ? jsgraph()->Constant( - Handle::cast(second_type->AsConstant()->Value()) + Handle::cast(second_type->AsHeapConstant()->Value()) ->length()) : effect = graph()->NewNode( simplified()->LoadField(AccessBuilder::ForStringLength()), @@ -980,8 +979,8 @@ Reduction JSTypedLowering::ReduceJSToLength(Node* node) { Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { // Try constant-folding of JSToNumber with constant inputs. Type* input_type = NodeProperties::GetType(input); - if (input_type->IsConstant()) { - Handle input_value = input_type->AsConstant()->Value(); + if (input_type->IsHeapConstant()) { + Handle input_value = input_type->AsHeapConstant()->Value(); if (input_value->IsString()) { return Replace(jsgraph()->Constant( String::ToNumber(Handle::cast(input_value)))); @@ -1280,13 +1279,13 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { Node* effect = r.effect(); Node* control = r.control(); - if (!r.right_type()->IsConstant() || - !r.right_type()->AsConstant()->Value()->IsJSFunction()) { + if (!r.right_type()->IsHeapConstant() || + !r.right_type()->AsHeapConstant()->Value()->IsJSFunction()) { return NoChange(); } Handle function = - Handle::cast(r.right_type()->AsConstant()->Value()); + Handle::cast(r.right_type()->AsHeapConstant()->Value()); Handle shared(function->shared(), isolate()); // Make sure the prototype of {function} is the %FunctionPrototype%, and it @@ -1485,9 +1484,9 @@ Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) { // with the global proxy unconditionally. if (receiver_type->Is(Type::NullOrUndefined()) || mode == ConvertReceiverMode::kNullOrUndefined) { - if (context_type->IsConstant()) { + if (context_type->IsHeapConstant()) { Handle global_proxy( - Handle::cast(context_type->AsConstant()->Value()) + Handle::cast(context_type->AsHeapConstant()->Value()) ->global_proxy(), isolate()); receiver = jsgraph()->Constant(global_proxy); @@ -1590,9 +1589,9 @@ Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) { Node* eglobal = effect; Node* rglobal; { - if (context_type->IsConstant()) { + if (context_type->IsHeapConstant()) { Handle global_proxy( - Handle::cast(context_type->AsConstant()->Value()) + Handle::cast(context_type->AsHeapConstant()->Value()) ->global_proxy(), isolate()); rglobal = jsgraph()->Constant(global_proxy); @@ -1715,10 +1714,10 @@ Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) { Node* control = NodeProperties::GetControlInput(node); // Check if {target} is a known JSFunction. - if (target_type->IsConstant() && - target_type->AsConstant()->Value()->IsJSFunction()) { + if (target_type->IsHeapConstant() && + target_type->AsHeapConstant()->Value()->IsJSFunction()) { Handle function = - Handle::cast(target_type->AsConstant()->Value()); + Handle::cast(target_type->AsHeapConstant()->Value()); Handle shared(function->shared(), isolate()); const int builtin_index = shared->construct_stub()->builtin_index(); const bool is_builtin = (builtin_index != -1); @@ -1800,10 +1799,10 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) { } // Check if {target} is a known JSFunction. - if (target_type->IsConstant() && - target_type->AsConstant()->Value()->IsJSFunction()) { + if (target_type->IsHeapConstant() && + target_type->AsHeapConstant()->Value()->IsJSFunction()) { Handle function = - Handle::cast(target_type->AsConstant()->Value()); + Handle::cast(target_type->AsHeapConstant()->Value()); Handle shared(function->shared(), isolate()); const int builtin_index = shared->code()->builtin_index(); const bool is_builtin = (builtin_index != -1); diff --git a/src/compiler/operation-typer.cc b/src/compiler/operation-typer.cc index ca693d1ae8..0cdb6d1031 100644 --- a/src/compiler/operation-typer.cc +++ b/src/compiler/operation-typer.cc @@ -19,14 +19,14 @@ namespace compiler { OperationTyper::OperationTyper(Isolate* isolate, Zone* zone) : zone_(zone), cache_(TypeCache::Get()) { Factory* factory = isolate->factory(); - infinity_ = Type::Constant(factory->infinity_value(), zone); - minus_infinity_ = Type::Constant(factory->minus_infinity_value(), zone); + infinity_ = Type::NewConstant(factory->infinity_value(), zone); + minus_infinity_ = Type::NewConstant(factory->minus_infinity_value(), zone); Type* truncating_to_zero = Type::MinusZeroOrNaN(); DCHECK(!truncating_to_zero->Maybe(Type::Integral32())); - singleton_false_ = Type::Constant(factory->false_value(), zone); - singleton_true_ = Type::Constant(factory->true_value(), zone); - singleton_the_hole_ = Type::Constant(factory->the_hole_value(), zone); + singleton_false_ = Type::HeapConstant(factory->false_value(), zone); + singleton_true_ = Type::HeapConstant(factory->true_value(), zone); + singleton_the_hole_ = Type::HeapConstant(factory->the_hole_value(), zone); signed32ish_ = Type::Union(Type::Signed32(), truncating_to_zero, zone); unsigned32ish_ = Type::Union(Type::Unsigned32(), truncating_to_zero, zone); } diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index 214097f65c..379d9ac8a1 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -1031,10 +1031,10 @@ class RepresentationSelector { // undefined, because these special oddballs are always in the root set. return kNoWriteBarrier; } - if (value_type->IsConstant() && - value_type->AsConstant()->Value()->IsHeapObject()) { + if (value_type->IsHeapConstant() && + value_type->AsHeapConstant()->Value()->IsHeapObject()) { Handle value_object = - Handle::cast(value_type->AsConstant()->Value()); + Handle::cast(value_type->AsHeapConstant()->Value()); RootIndexMap root_index_map(jsgraph_->isolate()); int root_index = root_index_map.Lookup(*value_object); if (root_index != RootIndexMap::kInvalidRootIndex && diff --git a/src/compiler/typed-optimization.cc b/src/compiler/typed-optimization.cc index c5e8648ca5..34661ee961 100644 --- a/src/compiler/typed-optimization.cc +++ b/src/compiler/typed-optimization.cc @@ -22,8 +22,9 @@ TypedOptimization::TypedOptimization(Editor* editor, dependencies_(dependencies), flags_(flags), jsgraph_(jsgraph), - true_type_(Type::Constant(factory()->true_value(), graph()->zone())), - false_type_(Type::Constant(factory()->false_value(), graph()->zone())), + true_type_(Type::HeapConstant(factory()->true_value(), graph()->zone())), + false_type_( + Type::HeapConstant(factory()->false_value(), graph()->zone())), type_cache_(TypeCache::Get()) {} TypedOptimization::~TypedOptimization() {} @@ -43,8 +44,9 @@ Reduction TypedOptimization::Reduce(Node* node) { // the Operator::kNoDeopt property). Type* upper = NodeProperties::GetType(node); if (upper->IsInhabited()) { - if (upper->IsConstant()) { - Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value()); + if (upper->IsHeapConstant()) { + Node* replacement = + jsgraph()->Constant(upper->AsHeapConstant()->Value()); ReplaceWithValue(node, replacement); return Changed(replacement); } else if (upper->Is(Type::MinusZero())) { @@ -96,10 +98,11 @@ Reduction TypedOptimization::Reduce(Node* node) { namespace { MaybeHandle GetStableMapFromObjectType(Type* object_type) { - if (object_type->IsConstant() && - object_type->AsConstant()->Value()->IsHeapObject()) { + if (object_type->IsHeapConstant() && + object_type->AsHeapConstant()->Value()->IsHeapObject()) { Handle object_map( - Handle::cast(object_type->AsConstant()->Value())->map()); + Handle::cast(object_type->AsHeapConstant()->Value()) + ->map()); if (object_map->is_stable()) return object_map; } return MaybeHandle(); @@ -121,8 +124,8 @@ Reduction TypedOptimization::ReduceCheckMaps(Node* node) { for (int i = 1; i < node->op()->ValueInputCount(); ++i) { Node* const map = NodeProperties::GetValueInput(node, i); Type* const map_type = NodeProperties::GetType(map); - if (map_type->IsConstant() && - map_type->AsConstant()->Value().is_identical_to(object_map)) { + if (map_type->IsHeapConstant() && + map_type->AsHeapConstant()->Value().is_identical_to(object_map)) { if (object_map->CanTransition()) { dependencies()->AssumeMapStable(object_map); } diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 936e5a0c45..ac6fda4877 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -41,9 +41,9 @@ Typer::Typer(Isolate* isolate, Graph* graph) Zone* zone = this->zone(); Factory* const factory = isolate->factory(); - singleton_false_ = Type::Constant(factory->false_value(), zone); - singleton_true_ = Type::Constant(factory->true_value(), zone); - singleton_the_hole_ = Type::Constant(factory->the_hole_value(), zone); + singleton_false_ = Type::HeapConstant(factory->false_value(), zone); + singleton_true_ = Type::HeapConstant(factory->true_value(), zone); + singleton_the_hole_ = Type::HeapConstant(factory->the_hole_value(), zone); falsish_ = Type::Union( Type::Undetectable(), Type::Union(Type::Union(singleton_false_, cache_.kZeroish, zone), @@ -604,15 +604,10 @@ Type* Typer::Visitor::TypeFloat64Constant(Node* node) { Type* Typer::Visitor::TypeNumberConstant(Node* node) { - Factory* f = isolate()->factory(); double number = OpParameter(node); - if (Type::IsInteger(number)) { - return Type::Range(number, number, zone()); - } - return Type::Constant(f->NewNumber(number), zone()); + return Type::NewConstant(number, zone()); } - Type* Typer::Visitor::TypeHeapConstant(Node* node) { return TypeConstant(OpParameter>(node)); } @@ -836,7 +831,7 @@ Type* Typer::Visitor::JSEqualTyper(Type* lhs, Type* rhs, Typer* t) { (lhs->Max() < rhs->Min() || lhs->Min() > rhs->Max())) { return t->singleton_false_; } - if (lhs->IsConstant() && rhs->Is(lhs)) { + if (lhs->IsHeapConstant() && rhs->Is(lhs)) { // Types are equal and are inhabited only by a single semantic value, // which is not nan due to the earlier check. return t->singleton_true_; @@ -873,7 +868,7 @@ Type* Typer::Visitor::JSStrictEqualTyper(Type* lhs, Type* rhs, Typer* t) { !lhs->Maybe(rhs)) { return t->singleton_false_; } - if (lhs->IsConstant() && rhs->Is(lhs)) { + if (lhs->IsHeapConstant() && rhs->Is(lhs)) { // Types are equal and are inhabited only by a single semantic value, // which is not nan due to the earlier check. return t->singleton_true_; @@ -907,7 +902,7 @@ Typer::Visitor::ComparisonOutcome Typer::Visitor::JSCompareTyper(Type* lhs, if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return kComparisonUndefined; ComparisonOutcome result; - if (lhs->IsConstant() && rhs->Is(lhs)) { + if (lhs->IsHeapConstant() && rhs->Is(lhs)) { // Types are equal and are inhabited only by a single semantic value. result = kComparisonFalse; } else if (lhs->Min() >= rhs->Max()) { @@ -1021,23 +1016,26 @@ Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) { Type* Typer::Visitor::JSTypeOfTyper(Type* type, Typer* t) { Factory* const f = t->isolate()->factory(); if (type->Is(Type::Boolean())) { - return Type::Constant(f->boolean_string(), t->zone()); + return Type::HeapConstant(f->boolean_string(), t->zone()); } else if (type->Is(Type::Number())) { - return Type::Constant(f->number_string(), t->zone()); + return Type::HeapConstant(f->number_string(), t->zone()); } else if (type->Is(Type::String())) { - return Type::Constant(f->string_string(), t->zone()); + return Type::HeapConstant(f->string_string(), t->zone()); } else if (type->Is(Type::Symbol())) { - return Type::Constant(f->symbol_string(), t->zone()); + return Type::HeapConstant(f->symbol_string(), t->zone()); } else if (type->Is(Type::Union(Type::Undefined(), Type::OtherUndetectable(), t->zone()))) { - return Type::Constant(f->undefined_string(), t->zone()); + return Type::HeapConstant(f->undefined_string(), t->zone()); } else if (type->Is(Type::Null())) { - return Type::Constant(f->object_string(), t->zone()); + return Type::HeapConstant(f->object_string(), t->zone()); } else if (type->Is(Type::Function())) { - return Type::Constant(f->function_string(), t->zone()); - } else if (type->IsConstant()) { - return Type::Constant( - Object::TypeOf(t->isolate(), type->AsConstant()->Value()), t->zone()); + return Type::HeapConstant(f->function_string(), t->zone()); + } else if (type->IsHeapConstant()) { + return Type::HeapConstant( + Object::TypeOf(t->isolate(), type->AsHeapConstant()->Value()), + t->zone()); + } else if (type->IsOtherNumberConstant()) { + return Type::HeapConstant(f->number_string(), t->zone()); } return Type::InternalizedString(); } @@ -1292,9 +1290,9 @@ Type* Typer::Visitor::TypeJSCallConstruct(Node* node) { Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) { - if (fun->IsConstant() && fun->AsConstant()->Value()->IsJSFunction()) { + if (fun->IsHeapConstant() && fun->AsHeapConstant()->Value()->IsJSFunction()) { Handle function = - Handle::cast(fun->AsConstant()->Value()); + Handle::cast(fun->AsHeapConstant()->Value()); if (function->shared()->HasBuiltinFunctionId()) { switch (function->shared()->builtin_function_id()) { case kMathRandom: @@ -1537,7 +1535,7 @@ Type* Typer::Visitor::TypePlainPrimitiveToFloat64(Node* node) { // static Type* Typer::Visitor::ReferenceEqualTyper(Type* lhs, Type* rhs, Typer* t) { - if (lhs->IsConstant() && rhs->Is(lhs)) { + if (lhs->IsHeapConstant() && rhs->Is(lhs)) { return t->singleton_true_; } return Type::Boolean(); @@ -1564,7 +1562,7 @@ Type* Typer::Visitor::StringFromCharCodeTyper(Type* type, Typer* t) { if (min == max) { uint32_t code = static_cast(min) & String::kMaxUtf16CodeUnitU; Handle string = f->LookupSingleCharacterStringFromCode(code); - return Type::Constant(string, t->zone()); + return Type::HeapConstant(string, t->zone()); } return Type::String(); } @@ -1577,7 +1575,7 @@ Type* Typer::Visitor::StringFromCodePointTyper(Type* type, Typer* t) { if (min == max) { uint32_t code = static_cast(min) & String::kMaxUtf16CodeUnitU; Handle string = f->LookupSingleCharacterStringFromCode(code); - return Type::Constant(string, t->zone()); + return Type::HeapConstant(string, t->zone()); } return Type::String(); } @@ -1752,7 +1750,7 @@ Type* Typer::Visitor::TypeConstant(Handle value) { if (Type::IsInteger(*value)) { return Type::Range(value->Number(), value->Number(), zone()); } - return Type::Constant(value, zone()); + return Type::NewConstant(value, zone()); } } // namespace compiler diff --git a/src/compiler/types.cc b/src/compiler/types.cc index 43d2f80483..3827cccd9f 100644 --- a/src/compiler/types.cc +++ b/src/compiler/types.cc @@ -56,12 +56,6 @@ bool Type::Contains(RangeType* lhs, RangeType* rhs) { return lhs->Min() <= rhs->Min() && rhs->Max() <= lhs->Max(); } -bool Type::Contains(RangeType* lhs, ConstantType* rhs) { - DisallowHeapAllocation no_allocation; - return IsInteger(*rhs->Value()) && lhs->Min() <= rhs->Value()->Number() && - rhs->Value()->Number() <= lhs->Max(); -} - bool Type::Contains(RangeType* range, i::Object* val) { DisallowHeapAllocation no_allocation; return IsInteger(val) && range->Min() <= val->Number() && @@ -82,7 +76,8 @@ double Type::Min() { return min; } if (this->IsRange()) return this->AsRange()->Min(); - if (this->IsConstant()) return this->AsConstant()->Value()->Number(); + if (this->IsOtherNumberConstant()) + return this->AsOtherNumberConstant()->Value(); UNREACHABLE(); return 0; } @@ -98,7 +93,8 @@ double Type::Max() { return max; } if (this->IsRange()) return this->AsRange()->Max(); - if (this->IsConstant()) return this->AsConstant()->Value()->Number(); + if (this->IsOtherNumberConstant()) + return this->AsOtherNumberConstant()->Value(); UNREACHABLE(); return 0; } @@ -139,7 +135,9 @@ Type::bitset BitsetType::Lub(Type* type) { } return bitset; } - if (type->IsConstant()) return type->AsConstant()->Lub(); + if (type->IsHeapConstant()) return type->AsHeapConstant()->Lub(); + if (type->IsOtherNumberConstant()) + return type->AsOtherNumberConstant()->Lub(); if (type->IsRange()) return type->AsRange()->Lub(); if (type->IsTuple()) return kOtherInternal; UNREACHABLE(); @@ -390,14 +388,43 @@ double BitsetType::Max(bitset bits) { return std::numeric_limits::quiet_NaN(); } +// static +bool OtherNumberConstantType::IsOtherNumberConstant(double value) { + // Not an integer, not NaN, and not -0. + return !std::isnan(value) && !Type::IsInteger(value) && + !i::IsMinusZero(value); +} + +// static +bool OtherNumberConstantType::IsOtherNumberConstant(Object* value) { + return value->IsHeapNumber() && + IsOtherNumberConstant(HeapNumber::cast(value)->value()); +} + +HeapConstantType::HeapConstantType(BitsetType::bitset bitset, + i::Handle object) + : TypeBase(kHeapConstant), bitset_(bitset), object_(object) { + // All number types should be expressed as Ranges, OtherNumberConstants, + // or bitsets (nan, negative-zero). + DCHECK(!object->IsSmi() && !object->IsHeapNumber()); +} + // ----------------------------------------------------------------------------- // Predicates. bool Type::SimplyEquals(Type* that) { DisallowHeapAllocation no_allocation; - if (this->IsConstant()) { - return that->IsConstant() && - *this->AsConstant()->Value() == *that->AsConstant()->Value(); + if (this->IsHeapConstant()) { + return that->IsHeapConstant() && + *this->AsHeapConstant()->Value() == *that->AsHeapConstant()->Value(); + } + if (this->IsOtherNumberConstant()) { + return that->IsOtherNumberConstant() && + this->AsOtherNumberConstant()->Value() == + that->AsOtherNumberConstant()->Value(); + } + if (this->IsRange()) { + if (that->IsHeapConstant() || that->IsOtherNumberConstant()) return false; } if (this->IsTuple()) { if (!that->IsTuple()) return false; @@ -446,9 +473,7 @@ bool Type::SlowIs(Type* that) { } if (that->IsRange()) { - return (this->IsRange() && Contains(that->AsRange(), this->AsRange())) || - (this->IsConstant() && - Contains(that->AsRange(), this->AsConstant())); + return (this->IsRange() && Contains(that->AsRange(), this->AsRange())); } if (this->IsRange()) return false; @@ -481,9 +506,6 @@ bool Type::Maybe(Type* that) { if (this->IsBitset() && that->IsBitset()) return true; if (this->IsRange()) { - if (that->IsConstant()) { - return Contains(this->AsRange(), that->AsConstant()); - } if (that->IsRange()) { return Overlap(this->AsRange(), that->AsRange()); } @@ -673,9 +695,6 @@ int Type::IntersectAux(Type* lhs, Type* rhs, UnionType* result, int size, } return size; } - if (rhs->IsConstant() && Contains(lhs->AsRange(), rhs->AsConstant())) { - return AddToUnion(rhs, result, size, zone); - } if (rhs->IsRange()) { RangeType::Limits lim = RangeType::Limits::Intersect( RangeType::Limits(lhs->AsRange()), RangeType::Limits(rhs->AsRange())); @@ -743,6 +762,29 @@ Type* Type::NormalizeRangeAndBitset(Type* range, bitset* bits, Zone* zone) { return RangeType::New(range_min, range_max, zone); } +Type* Type::NewConstant(double value, Zone* zone) { + if (IsInteger(value)) { + return Range(value, value, zone); + } else if (i::IsMinusZero(value)) { + return Type::MinusZero(); + } else if (std::isnan(value)) { + return Type::NaN(); + } + + DCHECK(OtherNumberConstantType::IsOtherNumberConstant(value)); + return OtherNumberConstant(value, zone); +} + +Type* Type::NewConstant(i::Handle value, Zone* zone) { + if (IsInteger(*value)) { + double v = value->Number(); + return Range(v, v, zone); + } else if (value->IsHeapNumber()) { + return NewConstant(value->Number(), zone); + } + return HeapConstant(value, zone); +} + Type* Type::Union(Type* type1, Type* type2, Zone* zone) { // Fast case: bit sets. if (type1->IsBitset() && type2->IsBitset()) { @@ -833,17 +875,14 @@ Type* Type::NormalizeUnion(Type* union_type, int size, Zone* zone) { return union_type; } -// ----------------------------------------------------------------------------- -// Iteration. - int Type::NumConstants() { DisallowHeapAllocation no_allocation; - if (this->IsConstant()) { + if (this->IsHeapConstant() || this->IsOtherNumberConstant()) { return 1; } else if (this->IsUnion()) { int result = 0; for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) { - if (this->AsUnion()->Get(i)->IsConstant()) ++result; + if (this->AsUnion()->Get(i)->IsHeapConstant()) ++result; } return result; } else { @@ -905,8 +944,11 @@ void Type::PrintTo(std::ostream& os) { DisallowHeapAllocation no_allocation; if (this->IsBitset()) { BitsetType::Print(os, this->AsBitset()); - } else if (this->IsConstant()) { - os << "Constant(" << Brief(*this->AsConstant()->Value()) << ")"; + } else if (this->IsHeapConstant()) { + os << "HeapConstant(" << Brief(*this->AsHeapConstant()->Value()) << ")"; + } else if (this->IsOtherNumberConstant()) { + os << "OtherNumberConstant(" << this->AsOtherNumberConstant()->Value() + << ")"; } else if (this->IsRange()) { std::ostream::fmtflags saved_flags = os.setf(std::ios::fixed); std::streamsize saved_precision = os.precision(0); diff --git a/src/compiler/types.h b/src/compiler/types.h index ef5bec3f9d..9b49f6430e 100644 --- a/src/compiler/types.h +++ b/src/compiler/types.h @@ -263,7 +263,7 @@ class TypeBase { protected: friend class Type; - enum Kind { kConstant, kTuple, kUnion, kRange }; + enum Kind { kHeapConstant, kOtherNumberConstant, kTuple, kUnion, kRange }; Kind kind() const { return kind_; } explicit TypeBase(Kind kind) : kind_(kind) {} @@ -287,7 +287,38 @@ class TypeBase { // ----------------------------------------------------------------------------- // Constant types. -class ConstantType : public TypeBase { +class OtherNumberConstantType : public TypeBase { + public: + double Value() { return value_; } + + static bool IsOtherNumberConstant(double value); + static bool IsOtherNumberConstant(Object* value); + + private: + friend class Type; + friend class BitsetType; + + static Type* New(double value, Zone* zone) { + return AsType(new (zone->New(sizeof(OtherNumberConstantType))) + OtherNumberConstantType(value)); // NOLINT + } + + static OtherNumberConstantType* cast(Type* type) { + DCHECK(IsKind(type, kOtherNumberConstant)); + return static_cast(FromType(type)); + } + + explicit OtherNumberConstantType(double value) + : TypeBase(kOtherNumberConstant), value_(value) { + CHECK(IsOtherNumberConstant(value)); + } + + BitsetType::bitset Lub() { return BitsetType::kOtherNumber; } + + double value_; +}; + +class HeapConstantType : public TypeBase { public: i::Handle Value() { return object_; } @@ -297,24 +328,22 @@ class ConstantType : public TypeBase { static Type* New(i::Handle value, Zone* zone) { BitsetType::bitset bitset = BitsetType::Lub(*value); - return AsType(new (zone->New(sizeof(ConstantType))) - ConstantType(bitset, value)); + return AsType(new (zone->New(sizeof(HeapConstantType))) + HeapConstantType(bitset, value)); } - static ConstantType* cast(Type* type) { - DCHECK(IsKind(type, kConstant)); - return static_cast(FromType(type)); + static HeapConstantType* cast(Type* type) { + DCHECK(IsKind(type, kHeapConstant)); + return static_cast(FromType(type)); } - ConstantType(BitsetType::bitset bitset, i::Handle object) - : TypeBase(kConstant), bitset_(bitset), object_(object) {} + HeapConstantType(BitsetType::bitset bitset, i::Handle object); BitsetType::bitset Lub() { return bitset_; } BitsetType::bitset bitset_; Handle object_; }; -// TODO(neis): Also cache value if numerical. // ----------------------------------------------------------------------------- // Range types. @@ -474,8 +503,11 @@ class Type { return BitsetType::New(BitsetType::UnsignedSmall()); } - static Type* Constant(i::Handle value, Zone* zone) { - return ConstantType::New(value, zone); + static Type* OtherNumberConstant(double value, Zone* zone) { + return OtherNumberConstantType::New(value, zone); + } + static Type* HeapConstant(i::Handle value, Zone* zone) { + return HeapConstantType::New(value, zone); } static Type* Range(double min, double max, Zone* zone) { return RangeType::New(min, max, zone); @@ -488,6 +520,10 @@ class Type { return tuple; } + // NewConstant is a factory that returns Constant, Range or Number. + static Type* NewConstant(i::Handle value, Zone* zone); + static Type* NewConstant(double value, Zone* zone); + static Type* Union(Type* type1, Type* type2, Zone* zone); static Type* Intersect(Type* type1, Type* type2, Zone* zone); @@ -515,10 +551,16 @@ class Type { // Inspection. bool IsRange() { return IsKind(TypeBase::kRange); } - bool IsConstant() { return IsKind(TypeBase::kConstant); } + bool IsHeapConstant() { return IsKind(TypeBase::kHeapConstant); } + bool IsOtherNumberConstant() { + return IsKind(TypeBase::kOtherNumberConstant); + } bool IsTuple() { return IsKind(TypeBase::kTuple); } - ConstantType* AsConstant() { return ConstantType::cast(this); } + HeapConstantType* AsHeapConstant() { return HeapConstantType::cast(this); } + OtherNumberConstantType* AsOtherNumberConstant() { + return OtherNumberConstantType::cast(this); + } RangeType* AsRange() { return RangeType::cast(this); } TupleType* AsTuple() { return TupleType::cast(this); } @@ -582,7 +624,6 @@ class Type { static bool Overlap(RangeType* lhs, RangeType* rhs); static bool Contains(RangeType* lhs, RangeType* rhs); - static bool Contains(RangeType* range, ConstantType* constant); static bool Contains(RangeType* range, i::Object* val); static int UpdateRange(Type* type, UnionType* result, int size, Zone* zone); diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc index dd1b3e3703..2e08bde0a0 100644 --- a/test/cctest/test-types.cc +++ b/test/cctest/test-types.cc @@ -31,12 +31,6 @@ static bool IsInteger(double x) { return nearbyint(x) == x && !i::IsMinusZero(x); // Allows for infinities. } - -static bool IsInteger(i::Object* x) { - return x->IsNumber() && IsInteger(x->Number()); -} - - typedef uint32_t bitset; struct Tests { @@ -113,8 +107,8 @@ struct Tests { for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { Type* t = *it; CHECK(1 == - this->IsBitset(t) + t->IsConstant() + t->IsRange() + - this->IsUnion(t)); + this->IsBitset(t) + t->IsHeapConstant() + t->IsRange() + + t->IsOtherNumberConstant() + this->IsUnion(t)); } } @@ -191,15 +185,25 @@ struct Tests { // Constructor for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle value = *vt; - Type* type = T.Constant(value); - CHECK(type->IsConstant()); + Type* type = T.NewConstant(value); + CHECK(type->IsHeapConstant() || type->IsOtherNumberConstant() || + type->IsRange()); } // Value attribute for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle value = *vt; - Type* type = T.Constant(value); - CHECK(*value == *type->AsConstant()->Value()); + Type* type = T.NewConstant(value); + if (type->IsHeapConstant()) { + CHECK(*value == *type->AsHeapConstant()->Value()); + } else if (type->IsOtherNumberConstant()) { + CHECK(value->IsHeapNumber()); + CHECK(value->Number() == type->AsOtherNumberConstant()->Value()); + } else { + CHECK(type->IsRange()); + double v = value->Number(); + CHECK(v == type->AsRange()->Min() && v == type->AsRange()->Max()); + } } // Functionality & Injectivity: Constant(V1) = Constant(V2) iff V1 = V2 @@ -207,61 +211,72 @@ struct Tests { for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) { Handle value1 = *vt1; Handle value2 = *vt2; - Type* type1 = T.Constant(value1); - Type* type2 = T.Constant(value2); - CHECK(Equal(type1, type2) == (*value1 == *value2)); + Type* type1 = T.NewConstant(value1); + Type* type2 = T.NewConstant(value2); + if (type1->IsOtherNumberConstant() && type2->IsOtherNumberConstant()) { + CHECK(Equal(type1, type2) == + (type1->AsOtherNumberConstant()->Value() == + type2->AsOtherNumberConstant()->Value())); + } else if (type1->IsRange() && type2->IsRange()) { + CHECK(Equal(type1, type2) == + ((type1->AsRange()->Min() == type2->AsRange()->Min()) && + (type1->AsRange()->Max() == type2->AsRange()->Max()))); + } else { + CHECK(Equal(type1, type2) == (*value1 == *value2)); + } } } // Typing of numbers Factory* fac = isolate->factory(); - CHECK(T.Constant(fac->NewNumber(0))->Is(T.UnsignedSmall)); - CHECK(T.Constant(fac->NewNumber(1))->Is(T.UnsignedSmall)); - CHECK(T.Constant(fac->NewNumber(0x3fffffff))->Is(T.UnsignedSmall)); - CHECK(T.Constant(fac->NewNumber(-1))->Is(T.Negative31)); - CHECK(T.Constant(fac->NewNumber(-0x3fffffff))->Is(T.Negative31)); - CHECK(T.Constant(fac->NewNumber(-0x40000000))->Is(T.Negative31)); - CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.Unsigned31)); - CHECK(!T.Constant(fac->NewNumber(0x40000000))->Is(T.Unsigned30)); - CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.Unsigned31)); - CHECK(!T.Constant(fac->NewNumber(0x7fffffff))->Is(T.Unsigned30)); - CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.Negative32)); - CHECK(!T.Constant(fac->NewNumber(-0x40000001))->Is(T.Negative31)); - CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.Negative32)); - CHECK(!T.Constant(fac->NewNumber(-0x7fffffff - 1))->Is(T.Negative31)); + CHECK(T.NewConstant(fac->NewNumber(0))->Is(T.UnsignedSmall)); + CHECK(T.NewConstant(fac->NewNumber(1))->Is(T.UnsignedSmall)); + CHECK(T.NewConstant(fac->NewNumber(0x3fffffff))->Is(T.UnsignedSmall)); + CHECK(T.NewConstant(fac->NewNumber(-1))->Is(T.Negative31)); + CHECK(T.NewConstant(fac->NewNumber(-0x3fffffff))->Is(T.Negative31)); + CHECK(T.NewConstant(fac->NewNumber(-0x40000000))->Is(T.Negative31)); + CHECK(T.NewConstant(fac->NewNumber(0x40000000))->Is(T.Unsigned31)); + CHECK(!T.NewConstant(fac->NewNumber(0x40000000))->Is(T.Unsigned30)); + CHECK(T.NewConstant(fac->NewNumber(0x7fffffff))->Is(T.Unsigned31)); + CHECK(!T.NewConstant(fac->NewNumber(0x7fffffff))->Is(T.Unsigned30)); + CHECK(T.NewConstant(fac->NewNumber(-0x40000001))->Is(T.Negative32)); + CHECK(!T.NewConstant(fac->NewNumber(-0x40000001))->Is(T.Negative31)); + CHECK(T.NewConstant(fac->NewNumber(-0x7fffffff))->Is(T.Negative32)); + CHECK(!T.NewConstant(fac->NewNumber(-0x7fffffff - 1))->Is(T.Negative31)); if (SmiValuesAre31Bits()) { - CHECK(!T.Constant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall)); - CHECK(!T.Constant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall)); - CHECK(!T.Constant(fac->NewNumber(-0x40000001))->Is(T.SignedSmall)); - CHECK(!T.Constant(fac->NewNumber(-0x7fffffff - 1))->Is(T.SignedSmall)); + CHECK(!T.NewConstant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall)); + CHECK(!T.NewConstant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall)); + CHECK(!T.NewConstant(fac->NewNumber(-0x40000001))->Is(T.SignedSmall)); + CHECK(!T.NewConstant(fac->NewNumber(-0x7fffffff - 1))->Is(T.SignedSmall)); } else { CHECK(SmiValuesAre32Bits()); - CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall)); - CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall)); - CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.SignedSmall)); - CHECK(T.Constant(fac->NewNumber(-0x7fffffff - 1))->Is(T.SignedSmall)); + CHECK(T.NewConstant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall)); + CHECK(T.NewConstant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall)); + CHECK(T.NewConstant(fac->NewNumber(-0x40000001))->Is(T.SignedSmall)); + CHECK(T.NewConstant(fac->NewNumber(-0x7fffffff - 1))->Is(T.SignedSmall)); } - CHECK(T.Constant(fac->NewNumber(0x80000000u))->Is(T.Unsigned32)); - CHECK(!T.Constant(fac->NewNumber(0x80000000u))->Is(T.Unsigned31)); - CHECK(T.Constant(fac->NewNumber(0xffffffffu))->Is(T.Unsigned32)); - CHECK(!T.Constant(fac->NewNumber(0xffffffffu))->Is(T.Unsigned31)); - CHECK(T.Constant(fac->NewNumber(0xffffffffu + 1.0))->Is(T.PlainNumber)); - CHECK(!T.Constant(fac->NewNumber(0xffffffffu + 1.0))->Is(T.Integral32)); - CHECK(T.Constant(fac->NewNumber(-0x7fffffff - 2.0))->Is(T.PlainNumber)); - CHECK(!T.Constant(fac->NewNumber(-0x7fffffff - 2.0))->Is(T.Integral32)); - CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.PlainNumber)); - CHECK(!T.Constant(fac->NewNumber(0.1))->Is(T.Integral32)); - CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.PlainNumber)); - CHECK(!T.Constant(fac->NewNumber(-10.1))->Is(T.Integral32)); - CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.PlainNumber)); - CHECK(!T.Constant(fac->NewNumber(10e60))->Is(T.Integral32)); - CHECK(T.Constant(fac->NewNumber(-1.0*0.0))->Is(T.MinusZero)); - CHECK(T.Constant(fac->NewNumber(std::numeric_limits::quiet_NaN())) - ->Is(T.NaN)); - CHECK(T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.PlainNumber)); - CHECK(!T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.Integral32)); - CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.PlainNumber)); - CHECK(!T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.Integral32)); + CHECK(T.NewConstant(fac->NewNumber(0x80000000u))->Is(T.Unsigned32)); + CHECK(!T.NewConstant(fac->NewNumber(0x80000000u))->Is(T.Unsigned31)); + CHECK(T.NewConstant(fac->NewNumber(0xffffffffu))->Is(T.Unsigned32)); + CHECK(!T.NewConstant(fac->NewNumber(0xffffffffu))->Is(T.Unsigned31)); + CHECK(T.NewConstant(fac->NewNumber(0xffffffffu + 1.0))->Is(T.PlainNumber)); + CHECK(!T.NewConstant(fac->NewNumber(0xffffffffu + 1.0))->Is(T.Integral32)); + CHECK(T.NewConstant(fac->NewNumber(-0x7fffffff - 2.0))->Is(T.PlainNumber)); + CHECK(!T.NewConstant(fac->NewNumber(-0x7fffffff - 2.0))->Is(T.Integral32)); + CHECK(T.NewConstant(fac->NewNumber(0.1))->Is(T.PlainNumber)); + CHECK(!T.NewConstant(fac->NewNumber(0.1))->Is(T.Integral32)); + CHECK(T.NewConstant(fac->NewNumber(-10.1))->Is(T.PlainNumber)); + CHECK(!T.NewConstant(fac->NewNumber(-10.1))->Is(T.Integral32)); + CHECK(T.NewConstant(fac->NewNumber(10e60))->Is(T.PlainNumber)); + CHECK(!T.NewConstant(fac->NewNumber(10e60))->Is(T.Integral32)); + CHECK(T.NewConstant(fac->NewNumber(-1.0 * 0.0))->Is(T.MinusZero)); + CHECK( + T.NewConstant(fac->NewNumber(std::numeric_limits::quiet_NaN())) + ->Is(T.NaN)); + CHECK(T.NewConstant(fac->NewNumber(V8_INFINITY))->Is(T.PlainNumber)); + CHECK(!T.NewConstant(fac->NewNumber(V8_INFINITY))->Is(T.Integral32)); + CHECK(T.NewConstant(fac->NewNumber(-V8_INFINITY))->Is(T.PlainNumber)); + CHECK(!T.NewConstant(fac->NewNumber(-V8_INFINITY))->Is(T.Integral32)); } void Range() { @@ -317,7 +332,7 @@ struct Tests { // Constant(V)->Is(Of(V)) for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle value = *vt; - Type* const_type = T.Constant(value); + Type* const_type = T.NewConstant(value); Type* of_type = T.Of(value); CHECK(const_type->Is(of_type)); } @@ -327,7 +342,7 @@ struct Tests { for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { Handle value = *vt; Type* type = *it; - Type* const_type = T.Constant(value); + Type* const_type = T.NewConstant(value); Type* of_type = T.Of(value); CHECK(!of_type->Is(type) || const_type->Is(type)); } @@ -338,7 +353,7 @@ struct Tests { for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { Handle value = *vt; Type* type = *it; - Type* const_type = T.Constant(value); + Type* const_type = T.NewConstant(value); Type* of_type = T.Of(value); CHECK(!const_type->Is(type) || of_type->Is(type) || type->Maybe(const_type)); @@ -521,10 +536,11 @@ struct Tests { Type* type2 = *j; CHECK(!type1->Is(type2) || this->IsBitset(type2) || this->IsUnion(type2) || this->IsUnion(type1) || - (type1->IsConstant() && type2->IsConstant()) || - (type1->IsConstant() && type2->IsRange()) || + (type1->IsHeapConstant() && type2->IsHeapConstant()) || (this->IsBitset(type1) && type2->IsRange()) || (type1->IsRange() && type2->IsRange()) || + (type1->IsOtherNumberConstant() && + type2->IsOtherNumberConstant()) || !type1->IsInhabited()); } } @@ -559,37 +575,27 @@ struct Tests { for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) { Handle value1 = *vt1; Handle value2 = *vt2; - Type* const_type1 = T.Constant(value1); - Type* const_type2 = T.Constant(value2); - CHECK(const_type1->Is(const_type2) == (*value1 == *value2)); + Type* const_type1 = T.NewConstant(value1); + Type* const_type2 = T.NewConstant(value2); + if (const_type1->IsOtherNumberConstant() && + const_type2->IsOtherNumberConstant()) { + CHECK(const_type1->Is(const_type2) == + (const_type1->AsOtherNumberConstant()->Value() == + const_type2->AsOtherNumberConstant()->Value())); + } else if (const_type1->IsRange() && const_type2->IsRange()) { + CHECK(Equal(const_type1, const_type2) == + ((const_type1->AsRange()->Min() == + const_type2->AsRange()->Min()) && + (const_type1->AsRange()->Max() == + const_type2->AsRange()->Max()))); + } else { + CHECK(const_type1->Is(const_type2) == (*value1 == *value2)); + } } } // Range-specific subtyping - // If IsInteger(v) then Constant(v)->Is(Range(v, v)). - for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - Type* type = *it; - if (type->IsConstant() && IsInteger(*type->AsConstant()->Value())) { - CHECK(type->Is(T.Range(type->AsConstant()->Value()->Number(), - type->AsConstant()->Value()->Number()))); - } - } - - // If Constant(x)->Is(Range(min,max)) then IsInteger(v) and min <= x <= max. - for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { - for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - Type* type1 = *it1; - Type* type2 = *it2; - if (type1->IsConstant() && type2->IsRange() && type1->Is(type2)) { - double x = type1->AsConstant()->Value()->Number(); - double min = type2->AsRange()->Min(); - double max = type2->AsRange()->Max(); - CHECK(IsInteger(x) && min <= x && x <= max); - } - } - } - // Lub(Range(x,y))->Is(T.Union(T.Integral32, T.OtherNumber)) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { Type* type = *it; @@ -712,9 +718,22 @@ struct Tests { for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) { Handle value1 = *vt1; Handle value2 = *vt2; - Type* const_type1 = T.Constant(value1); - Type* const_type2 = T.Constant(value2); - CHECK(const_type1->Maybe(const_type2) == (*value1 == *value2)); + Type* const_type1 = T.NewConstant(value1); + Type* const_type2 = T.NewConstant(value2); + if (const_type1->IsOtherNumberConstant() && + const_type2->IsOtherNumberConstant()) { + CHECK(const_type1->Maybe(const_type2) == + (const_type1->AsOtherNumberConstant()->Value() == + const_type2->AsOtherNumberConstant()->Value())); + } else if (const_type1->IsRange() && const_type2->IsRange()) { + CHECK(Equal(const_type1, const_type2) == + ((const_type1->AsRange()->Min() == + const_type2->AsRange()->Min()) && + (const_type1->AsRange()->Max() == + const_type2->AsRange()->Max()))); + } else { + CHECK(const_type1->Maybe(const_type2) == (*value1 == *value2)); + } } } @@ -1054,20 +1073,6 @@ struct Tests { CHECK(type1->Max() == range->Max()); } } - - // GetRange(Union(Constant(x), Range(min,max))) == Range(min, max). - for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { - for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - Type* type1 = *it1; - Type* type2 = *it2; - if (type1->IsConstant() && type2->IsRange()) { - Type* u = T.Union(type1, type2); - - CHECK(type2->Min() == u->GetRange()->Min()); - CHECK(type2->Max() == u->GetRange()->Max()); - } - } - } } }; diff --git a/test/cctest/types-fuzz.h b/test/cctest/types-fuzz.h index 16bfd737ea..f4a16dd19a 100644 --- a/test/cctest/types-fuzz.h +++ b/test/cctest/types-fuzz.h @@ -54,27 +54,37 @@ class Types { JS_OBJECT_TYPE, JSObject::kHeaderSize); smi = handle(Smi::FromInt(666), isolate); + boxed_smi = isolate->factory()->NewHeapNumber(666); signed32 = isolate->factory()->NewHeapNumber(0x40000000); + float1 = isolate->factory()->NewHeapNumber(1.53); + float2 = isolate->factory()->NewHeapNumber(0.53); + // float3 is identical to float1 in order to test that OtherNumberConstant + // types are equal by double value and not by handle pointer value. + float3 = isolate->factory()->NewHeapNumber(1.53); object1 = isolate->factory()->NewJSObjectFromMap(object_map); object2 = isolate->factory()->NewJSObjectFromMap(object_map); array = isolate->factory()->NewJSArray(20); uninitialized = isolate->factory()->uninitialized_value(); - SmiConstant = Type::Constant(smi, zone); - Signed32Constant = Type::Constant(signed32, zone); + SmiConstant = Type::NewConstant(smi, zone); + Signed32Constant = Type::NewConstant(signed32, zone); - ObjectConstant1 = Type::Constant(object1, zone); - ObjectConstant2 = Type::Constant(object2, zone); - ArrayConstant = Type::Constant(array, zone); - UninitializedConstant = Type::Constant(uninitialized, zone); + ObjectConstant1 = Type::HeapConstant(object1, zone); + ObjectConstant2 = Type::HeapConstant(object2, zone); + ArrayConstant = Type::HeapConstant(array, zone); + UninitializedConstant = Type::HeapConstant(uninitialized, zone); values.push_back(smi); + values.push_back(boxed_smi); values.push_back(signed32); values.push_back(object1); values.push_back(object2); values.push_back(array); values.push_back(uninitialized); + values.push_back(float1); + values.push_back(float2); + values.push_back(float3); for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) { - types.push_back(Type::Constant(*it, zone)); + types.push_back(Type::NewConstant(*it, zone)); } integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY)); @@ -98,7 +108,11 @@ class Types { Handle object_map; Handle smi; + Handle boxed_smi; Handle signed32; + Handle float1; + Handle float2; + Handle float3; Handle object1; Handle object2; Handle array; @@ -129,8 +143,12 @@ class Types { Type* Of(Handle value) { return Type::Of(value, zone_); } - Type* Constant(Handle value) { - return Type::Constant(value, zone_); + Type* NewConstant(Handle value) { + return Type::NewConstant(value, zone_); + } + + Type* HeapConstant(Handle value) { + return Type::HeapConstant(value, zone_); } Type* Range(double min, double max) { return Type::Range(min, max, zone_); } @@ -170,7 +188,7 @@ class Types { } case 1: { // constant int i = rng_->NextInt(static_cast(values.size())); - return Type::Constant(values[i], zone_); + return Type::NewConstant(values[i], zone_); } case 2: { // range int i = rng_->NextInt(static_cast(integers.size())); diff --git a/test/unittests/compiler/graph-unittest.cc b/test/unittests/compiler/graph-unittest.cc index 399f985370..e562e511ec 100644 --- a/test/unittests/compiler/graph-unittest.cc +++ b/test/unittests/compiler/graph-unittest.cc @@ -54,7 +54,7 @@ Node* GraphTest::NumberConstant(volatile double value) { Node* GraphTest::HeapConstant(const Handle& value) { Node* node = graph()->NewNode(common()->HeapConstant(value)); - Type* type = Type::Constant(value, zone()); + Type* type = Type::HeapConstant(value, zone()); NodeProperties::SetType(node, type); return node; } diff --git a/test/unittests/compiler/js-create-lowering-unittest.cc b/test/unittests/compiler/js-create-lowering-unittest.cc index ebb1633401..cf29553564 100644 --- a/test/unittests/compiler/js-create-lowering-unittest.cc +++ b/test/unittests/compiler/js-create-lowering-unittest.cc @@ -65,7 +65,7 @@ class JSCreateLoweringTest : public TypedGraphTest { TEST_F(JSCreateLoweringTest, JSCreate) { Handle function = isolate()->object_function(); - Node* const target = Parameter(Type::Constant(function, graph()->zone())); + Node* const target = Parameter(Type::HeapConstant(function, graph()->zone())); Node* const context = Parameter(Type::Any()); Node* const effect = graph()->start(); Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target, diff --git a/test/unittests/compiler/typed-optimization-unittest.cc b/test/unittests/compiler/typed-optimization-unittest.cc index d73c72d4e0..4b583fd461 100644 --- a/test/unittests/compiler/typed-optimization-unittest.cc +++ b/test/unittests/compiler/typed-optimization-unittest.cc @@ -88,7 +88,7 @@ class TypedOptimizationTest : public TypedGraphTest { TEST_F(TypedOptimizationTest, ParameterWithMinusZero) { { Reduction r = Reduce( - Parameter(Type::Constant(factory()->minus_zero_value(), zone()))); + Parameter(Type::NewConstant(factory()->minus_zero_value(), zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0)); } @@ -98,9 +98,9 @@ TEST_F(TypedOptimizationTest, ParameterWithMinusZero) { EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0)); } { - Reduction r = Reduce(Parameter( - Type::Union(Type::MinusZero(), - Type::Constant(factory()->NewNumber(0), zone()), zone()))); + Reduction r = Reduce(Parameter(Type::Union( + Type::MinusZero(), Type::NewConstant(factory()->NewNumber(0), zone()), + zone()))); EXPECT_FALSE(r.Changed()); } } @@ -108,7 +108,7 @@ TEST_F(TypedOptimizationTest, ParameterWithMinusZero) { TEST_F(TypedOptimizationTest, ParameterWithNull) { Handle null = factory()->null_value(); { - Reduction r = Reduce(Parameter(Type::Constant(null, zone()))); + Reduction r = Reduce(Parameter(Type::NewConstant(null, zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsHeapConstant(null)); } @@ -125,13 +125,13 @@ TEST_F(TypedOptimizationTest, ParameterWithNaN) { std::numeric_limits::signaling_NaN()}; TRACED_FOREACH(double, nan, kNaNs) { Handle constant = factory()->NewNumber(nan); - Reduction r = Reduce(Parameter(Type::Constant(constant, zone()))); + Reduction r = Reduce(Parameter(Type::NewConstant(constant, zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); } { Reduction r = - Reduce(Parameter(Type::Constant(factory()->nan_value(), zone()))); + Reduce(Parameter(Type::NewConstant(factory()->nan_value(), zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); } @@ -145,7 +145,7 @@ TEST_F(TypedOptimizationTest, ParameterWithNaN) { TEST_F(TypedOptimizationTest, ParameterWithPlainNumber) { TRACED_FOREACH(double, value, kFloat64Values) { Handle constant = factory()->NewNumber(value); - Reduction r = Reduce(Parameter(Type::Constant(constant, zone()))); + Reduction r = Reduce(Parameter(Type::NewConstant(constant, zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsNumberConstant(value)); } @@ -164,7 +164,7 @@ TEST_F(TypedOptimizationTest, ParameterWithUndefined) { EXPECT_THAT(r.replacement(), IsHeapConstant(undefined)); } { - Reduction r = Reduce(Parameter(Type::Constant(undefined, zone()))); + Reduction r = Reduce(Parameter(Type::NewConstant(undefined, zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsHeapConstant(undefined)); } @@ -182,9 +182,9 @@ TEST_F(TypedOptimizationTest, JSToBooleanWithFalsish) { Type::Undefined(), Type::Union( Type::Undetectable(), - Type::Union( - Type::Constant(factory()->false_value(), zone()), - Type::Range(0.0, 0.0, zone()), zone()), + Type::Union(Type::NewConstant( + factory()->false_value(), zone()), + Type::Range(0.0, 0.0, zone()), zone()), zone()), zone()), zone()), @@ -201,7 +201,7 @@ TEST_F(TypedOptimizationTest, JSToBooleanWithFalsish) { TEST_F(TypedOptimizationTest, JSToBooleanWithTruish) { Node* input = Parameter( Type::Union( - Type::Constant(factory()->true_value(), zone()), + Type::NewConstant(factory()->true_value(), zone()), Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()), zone()), 0); diff --git a/test/unittests/compiler/typer-unittest.cc b/test/unittests/compiler/typer-unittest.cc index ca5c1cae45..1e860ae1ad 100644 --- a/test/unittests/compiler/typer-unittest.cc +++ b/test/unittests/compiler/typer-unittest.cc @@ -135,7 +135,7 @@ class TyperTest : public TypedGraphTest { for (int x1 = lmin; x1 < lmin + width; x1++) { for (int x2 = rmin; x2 < rmin + width; x2++) { double result_value = opfun(x1, x2); - Type* result_type = Type::Constant( + Type* result_type = Type::NewConstant( isolate()->factory()->NewNumber(result_value), zone()); EXPECT_TRUE(result_type->Is(expected_type)); } @@ -156,7 +156,7 @@ class TyperTest : public TypedGraphTest { double x1 = RandomInt(r1->AsRange()); double x2 = RandomInt(r2->AsRange()); double result_value = opfun(x1, x2); - Type* result_type = Type::Constant( + Type* result_type = Type::NewConstant( isolate()->factory()->NewNumber(result_value), zone()); EXPECT_TRUE(result_type->Is(expected_type)); } @@ -173,10 +173,10 @@ class TyperTest : public TypedGraphTest { double x1 = RandomInt(r1->AsRange()); double x2 = RandomInt(r2->AsRange()); bool result_value = opfun(x1, x2); - Type* result_type = - Type::Constant(result_value ? isolate()->factory()->true_value() - : isolate()->factory()->false_value(), - zone()); + Type* result_type = Type::NewConstant( + result_value ? isolate()->factory()->true_value() + : isolate()->factory()->false_value(), + zone()); EXPECT_TRUE(result_type->Is(expected_type)); } } @@ -192,7 +192,7 @@ class TyperTest : public TypedGraphTest { int32_t x1 = static_cast(RandomInt(r1->AsRange())); int32_t x2 = static_cast(RandomInt(r2->AsRange())); double result_value = opfun(x1, x2); - Type* result_type = Type::Constant( + Type* result_type = Type::NewConstant( isolate()->factory()->NewNumber(result_value), zone()); EXPECT_TRUE(result_type->Is(expected_type)); }