Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index 137829e..c1f816d 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -2,220 +2,71 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "src/compiler/typer.h"
+
+#include "src/base/flags.h"
#include "src/bootstrapper.h"
-#include "src/compiler/graph-inl.h"
+#include "src/compilation-dependencies.h"
+#include "src/compiler/common-operator.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/node.h"
-#include "src/compiler/node-properties-inl.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/simplified-operator.h"
-#include "src/compiler/typer.h"
+#include "src/objects-inl.h"
+#include "src/type-cache.h"
namespace v8 {
namespace internal {
namespace compiler {
-#define NATIVE_TYPES(V) \
- V(Int8) \
- V(Uint8) \
- V(Int16) \
- V(Uint16) \
- V(Int32) \
- V(Uint32) \
- V(Float32) \
- V(Float64)
-
-enum LazyCachedType {
- kNumberFunc0,
- kNumberFunc1,
- kNumberFunc2,
- kImulFunc,
- kClz32Func,
- kArrayBufferFunc,
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- k##Type, k##Type##Array, k##Type##ArrayFunc,
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
- kNumLazyCachedTypes
-};
-
-
-// Constructs and caches types lazily.
-// TODO(turbofan): these types could be globally cached or cached per isolate.
-class LazyTypeCache FINAL : public ZoneObject {
- public:
- explicit LazyTypeCache(Zone* zone) : zone_(zone) {
- memset(cache_, 0, sizeof(cache_));
- }
-
- inline Type* Get(LazyCachedType type) {
- int index = static_cast<int>(type);
- DCHECK(index < kNumLazyCachedTypes);
- if (cache_[index] == NULL) cache_[index] = Create(type);
- return cache_[index];
- }
-
- private:
- Type* Create(LazyCachedType type) {
- switch (type) {
- case kInt8:
- return CreateNative(CreateRange<int8_t>(), Type::UntaggedSigned8());
- case kUint8:
- return CreateNative(CreateRange<uint8_t>(), Type::UntaggedUnsigned8());
- case kInt16:
- return CreateNative(CreateRange<int16_t>(), Type::UntaggedSigned16());
- case kUint16:
- return CreateNative(CreateRange<uint16_t>(),
- Type::UntaggedUnsigned16());
- case kInt32:
- return CreateNative(Type::Signed32(), Type::UntaggedSigned32());
- case kUint32:
- return CreateNative(Type::Unsigned32(), Type::UntaggedUnsigned32());
- case kFloat32:
- return CreateNative(Type::Number(), Type::UntaggedFloat32());
- case kFloat64:
- return CreateNative(Type::Number(), Type::UntaggedFloat64());
- case kUint8Clamped:
- return Get(kUint8);
- case kNumberFunc0:
- return Type::Function(Type::Number(), zone());
- case kNumberFunc1:
- return Type::Function(Type::Number(), Type::Number(), zone());
- case kNumberFunc2:
- return Type::Function(Type::Number(), Type::Number(), Type::Number(),
- zone());
- case kImulFunc:
- return Type::Function(Type::Signed32(), Type::Integral32(),
- Type::Integral32(), zone());
- case kClz32Func:
- return Type::Function(CreateRange(0, 32), Type::Number(), zone());
- case kArrayBufferFunc:
- return Type::Function(Type::Object(zone()), Type::Unsigned32(), zone());
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case k##Type##Array: \
- return CreateArray(Get(k##Type)); \
- case k##Type##ArrayFunc: \
- return CreateArrayFunction(Get(k##Type##Array));
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
- case kNumLazyCachedTypes:
- break;
- }
- UNREACHABLE();
- return NULL;
- }
-
- Type* CreateArray(Type* element) const {
- return Type::Array(element, zone());
- }
-
- Type* CreateArrayFunction(Type* array) const {
- Type* arg1 = Type::Union(Type::Unsigned32(), Type::Object(), zone());
- Type* arg2 = Type::Union(Type::Unsigned32(), Type::Undefined(), zone());
- Type* arg3 = arg2;
- return Type::Function(array, arg1, arg2, arg3, zone());
- }
-
- Type* CreateNative(Type* semantic, Type* representation) const {
- return Type::Intersect(semantic, representation, zone());
- }
-
- template <typename T>
- Type* CreateRange() const {
- return CreateRange(std::numeric_limits<T>::min(),
- std::numeric_limits<T>::max());
- }
-
- Type* CreateRange(double min, double max) const {
- return Type::Range(factory()->NewNumber(min), factory()->NewNumber(max),
- zone());
- }
-
- Factory* factory() const { return isolate()->factory(); }
- Isolate* isolate() const { return zone()->isolate(); }
- Zone* zone() const { return zone_; }
-
- Type* cache_[kNumLazyCachedTypes];
- Zone* zone_;
-};
-
-
-class Typer::Decorator FINAL : public GraphDecorator {
+class Typer::Decorator final : public GraphDecorator {
public:
explicit Decorator(Typer* typer) : typer_(typer) {}
- void Decorate(Node* node) FINAL;
+ void Decorate(Node* node) final;
private:
- Typer* typer_;
+ Typer* const typer_;
};
-Typer::Typer(Graph* graph, MaybeHandle<Context> context)
- : graph_(graph),
- context_(context),
- decorator_(NULL),
- cache_(new (graph->zone()) LazyTypeCache(graph->zone())),
- weaken_min_limits_(graph->zone()),
- weaken_max_limits_(graph->zone()) {
+Typer::Typer(Isolate* isolate, Graph* graph, Flags flags,
+ CompilationDependencies* dependencies,
+ Type::FunctionType* function_type)
+ : isolate_(isolate),
+ graph_(graph),
+ flags_(flags),
+ dependencies_(dependencies),
+ function_type_(function_type),
+ decorator_(nullptr),
+ cache_(TypeCache::Get()) {
Zone* zone = this->zone();
- Factory* f = zone->isolate()->factory();
+ Factory* const factory = isolate->factory();
- Handle<Object> zero = f->NewNumber(0);
- Handle<Object> one = f->NewNumber(1);
- Handle<Object> infinity = f->NewNumber(+V8_INFINITY);
- Handle<Object> minusinfinity = f->NewNumber(-V8_INFINITY);
-
- Type* number = Type::Number();
- Type* signed32 = Type::Signed32();
- Type* unsigned32 = Type::Unsigned32();
- Type* nan_or_minuszero = Type::Union(Type::NaN(), Type::MinusZero(), zone);
+ Type* infinity = Type::Constant(factory->infinity_value(), zone);
+ Type* minus_infinity = Type::Constant(factory->minus_infinity_value(), zone);
+ // TODO(neis): Unfortunately, the infinities created in other places might
+ // be different ones (eg the result of NewNumber in TypeNumberConstant).
Type* truncating_to_zero =
- Type::Union(Type::Union(Type::Constant(infinity, zone),
- Type::Constant(minusinfinity, zone), zone),
- nan_or_minuszero, zone);
+ Type::Union(Type::Union(infinity, minus_infinity, zone),
+ Type::MinusZeroOrNaN(), zone);
+ DCHECK(!truncating_to_zero->Maybe(Type::Integral32()));
- boolean_or_number = Type::Union(Type::Boolean(), Type::Number(), zone);
- undefined_or_null = Type::Union(Type::Undefined(), Type::Null(), zone);
- undefined_or_number = Type::Union(Type::Undefined(), Type::Number(), zone);
- singleton_false = Type::Constant(f->false_value(), zone);
- singleton_true = Type::Constant(f->true_value(), zone);
- singleton_zero = Type::Range(zero, zero, zone);
- singleton_one = Type::Range(one, one, zone);
- zero_or_one = Type::Union(singleton_zero, singleton_one, zone);
- zeroish = Type::Union(singleton_zero, nan_or_minuszero, zone);
- signed32ish = Type::Union(signed32, truncating_to_zero, zone);
- unsigned32ish = Type::Union(unsigned32, truncating_to_zero, zone);
- falsish = Type::Union(Type::Undetectable(),
- Type::Union(Type::Union(singleton_false, zeroish, zone),
- undefined_or_null, zone),
- zone);
- truish = Type::Union(
- singleton_true,
+ 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);
+ signed32ish_ = Type::Union(Type::Signed32(), truncating_to_zero, zone);
+ unsigned32ish_ = Type::Union(Type::Unsigned32(), truncating_to_zero, zone);
+ falsish_ = Type::Union(
+ Type::Undetectable(),
+ Type::Union(
+ Type::Union(Type::Union(singleton_false_, cache_.kZeroish, zone),
+ Type::NullOrUndefined(), zone),
+ singleton_the_hole_, zone),
+ zone);
+ truish_ = Type::Union(
+ singleton_true_,
Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone), zone);
- integer = Type::Range(minusinfinity, infinity, zone);
- weakint = Type::Union(integer, nan_or_minuszero, zone);
-
- number_fun0_ = Type::Function(number, zone);
- number_fun1_ = Type::Function(number, number, zone);
- number_fun2_ = Type::Function(number, number, number, zone);
-
- weakint_fun1_ = Type::Function(weakint, number, zone);
- random_fun_ = Type::Function(Type::OrderedNumber(), zone);
-
- const int limits_count = 20;
-
- weaken_min_limits_.reserve(limits_count + 1);
- weaken_max_limits_.reserve(limits_count + 1);
-
- double limit = 1 << 30;
- weaken_min_limits_.push_back(f->NewNumber(0));
- weaken_max_limits_.push_back(f->NewNumber(0));
- for (int i = 0; i < limits_count; i++) {
- weaken_min_limits_.push_back(f->NewNumber(-limit));
- weaken_max_limits_.push_back(f->NewNumber(limit - 1));
- limit *= 2;
- }
decorator_ = new (zone) Decorator(this);
graph_->AddDecorator(decorator_);
@@ -229,21 +80,23 @@
class Typer::Visitor : public Reducer {
public:
- explicit Visitor(Typer* typer) : typer_(typer) {}
+ explicit Visitor(Typer* typer)
+ : typer_(typer), weakened_nodes_(typer->zone()) {}
- Reduction Reduce(Node* node) OVERRIDE {
+ Reduction Reduce(Node* node) override {
if (node->op()->ValueOutputCount() == 0) return NoChange();
switch (node->opcode()) {
#define DECLARE_CASE(x) \
case IrOpcode::k##x: \
- return UpdateBounds(node, TypeBinaryOp(node, x##Typer));
+ return UpdateType(node, TypeBinaryOp(node, x##Typer));
JS_SIMPLE_BINOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(x) \
case IrOpcode::k##x: \
- return UpdateBounds(node, Type##x(node));
+ return UpdateType(node, Type##x(node));
DECLARE_CASE(Start)
+ DECLARE_CASE(IfException)
// VALUE_OP_LIST without JS_SIMPLE_BINOP_LIST:
COMMON_OP_LIST(DECLARE_CASE)
SIMPLIFIED_OP_LIST(DECLARE_CASE)
@@ -255,15 +108,30 @@
#undef DECLARE_CASE
#define DECLARE_CASE(x) case IrOpcode::k##x:
+ DECLARE_CASE(Loop)
+ DECLARE_CASE(Branch)
+ DECLARE_CASE(IfTrue)
+ DECLARE_CASE(IfFalse)
+ DECLARE_CASE(IfSuccess)
+ DECLARE_CASE(Switch)
+ DECLARE_CASE(IfValue)
+ DECLARE_CASE(IfDefault)
+ DECLARE_CASE(Merge)
+ DECLARE_CASE(Deoptimize)
+ DECLARE_CASE(Return)
+ DECLARE_CASE(TailCall)
+ DECLARE_CASE(Terminate)
+ DECLARE_CASE(OsrNormalEntry)
+ DECLARE_CASE(OsrLoopEntry)
+ DECLARE_CASE(Throw)
DECLARE_CASE(End)
- INNER_CONTROL_OP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
break;
}
return NoChange();
}
- Bounds TypeNode(Node* node) {
+ Type* TypeNode(Node* node) {
switch (node->opcode()) {
#define DECLARE_CASE(x) \
case IrOpcode::k##x: return TypeBinaryOp(node, x##Typer);
@@ -272,6 +140,7 @@
#define DECLARE_CASE(x) case IrOpcode::k##x: return Type##x(node);
DECLARE_CASE(Start)
+ DECLARE_CASE(IfException)
// VALUE_OP_LIST without JS_SIMPLE_BINOP_LIST:
COMMON_OP_LIST(DECLARE_CASE)
SIMPLIFIED_OP_LIST(DECLARE_CASE)
@@ -283,64 +152,93 @@
#undef DECLARE_CASE
#define DECLARE_CASE(x) case IrOpcode::k##x:
+ DECLARE_CASE(Loop)
+ DECLARE_CASE(Branch)
+ DECLARE_CASE(IfTrue)
+ DECLARE_CASE(IfFalse)
+ DECLARE_CASE(IfSuccess)
+ DECLARE_CASE(Switch)
+ DECLARE_CASE(IfValue)
+ DECLARE_CASE(IfDefault)
+ DECLARE_CASE(Merge)
+ DECLARE_CASE(Deoptimize)
+ DECLARE_CASE(Return)
+ DECLARE_CASE(TailCall)
+ DECLARE_CASE(Terminate)
+ DECLARE_CASE(OsrNormalEntry)
+ DECLARE_CASE(OsrLoopEntry)
+ DECLARE_CASE(Throw)
DECLARE_CASE(End)
- INNER_CONTROL_OP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
break;
}
UNREACHABLE();
- return Bounds();
+ return nullptr;
}
Type* TypeConstant(Handle<Object> value);
private:
Typer* typer_;
- MaybeHandle<Context> context_;
+ ZoneSet<NodeId> weakened_nodes_;
-#define DECLARE_METHOD(x) inline Bounds Type##x(Node* node);
+#define DECLARE_METHOD(x) inline Type* Type##x(Node* node);
DECLARE_METHOD(Start)
+ DECLARE_METHOD(IfException)
VALUE_OP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
- Bounds BoundsOrNone(Node* node) {
- return NodeProperties::IsTyped(node) ? NodeProperties::GetBounds(node)
- : Bounds(Type::None());
+ Type* TypeOrNone(Node* node) {
+ return NodeProperties::IsTyped(node) ? NodeProperties::GetType(node)
+ : Type::None();
}
- Bounds Operand(Node* node, int i) {
+ Type* Operand(Node* node, int i) {
Node* operand_node = NodeProperties::GetValueInput(node, i);
- return BoundsOrNone(operand_node);
+ return TypeOrNone(operand_node);
}
- Bounds ContextOperand(Node* node) {
- Bounds result = BoundsOrNone(NodeProperties::GetContextInput(node));
- DCHECK(result.upper->Maybe(Type::Internal()));
- // TODO(rossberg): More precisely, instead of the above assertion, we should
- // back-propagate the constraint that it has to be a subtype of Internal.
- return result;
- }
-
- Type* Weaken(Type* current_type, Type* previous_type);
+ Type* WrapContextTypeForInput(Node* node);
+ Type* Weaken(Node* node, Type* current_type, Type* previous_type);
Zone* zone() { return typer_->zone(); }
Isolate* isolate() { return typer_->isolate(); }
Graph* graph() { return typer_->graph(); }
- MaybeHandle<Context> context() { return typer_->context(); }
+ Typer::Flags flags() const { return typer_->flags(); }
+ CompilationDependencies* dependencies() const {
+ return typer_->dependencies();
+ }
+
+ void SetWeakened(NodeId node_id) { weakened_nodes_.insert(node_id); }
+ bool IsWeakened(NodeId node_id) {
+ return weakened_nodes_.find(node_id) != weakened_nodes_.end();
+ }
typedef Type* (*UnaryTyperFun)(Type*, Typer* t);
typedef Type* (*BinaryTyperFun)(Type*, Type*, Typer* t);
- Bounds TypeUnaryOp(Node* node, UnaryTyperFun);
- Bounds TypeBinaryOp(Node* node, BinaryTyperFun);
+ Type* TypeUnaryOp(Node* node, UnaryTyperFun);
+ Type* TypeBinaryOp(Node* node, BinaryTyperFun);
+ enum ComparisonOutcomeFlags {
+ kComparisonTrue = 1,
+ kComparisonFalse = 2,
+ kComparisonUndefined = 4
+ };
+ typedef base::Flags<ComparisonOutcomeFlags> ComparisonOutcome;
+
+ static ComparisonOutcome Invert(ComparisonOutcome, Typer*);
static Type* Invert(Type*, Typer*);
- static Type* FalsifyUndefined(Type*, Typer*);
+ static Type* FalsifyUndefined(ComparisonOutcome, Typer*);
static Type* Rangify(Type*, Typer*);
static Type* ToPrimitive(Type*, Typer*);
static Type* ToBoolean(Type*, Typer*);
+ static Type* ToInteger(Type*, Typer*);
+ static Type* ToLength(Type*, Typer*);
+ static Type* ToName(Type*, Typer*);
static Type* ToNumber(Type*, Typer*);
+ static Type* ToObject(Type*, Typer*);
static Type* ToString(Type*, Typer*);
static Type* NumberToInt32(Type*, Typer*);
static Type* NumberToUint32(Type*, Typer*);
@@ -351,68 +249,52 @@
static Type* JSDivideRanger(Type::RangeType*, Type::RangeType*, Typer*);
static Type* JSModulusRanger(Type::RangeType*, Type::RangeType*, Typer*);
- static Type* JSCompareTyper(Type*, Type*, Typer*);
+ static ComparisonOutcome JSCompareTyper(Type*, Type*, Typer*);
#define DECLARE_METHOD(x) static Type* x##Typer(Type*, Type*, Typer*);
JS_SIMPLE_BINOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
- static Type* JSUnaryNotTyper(Type*, Typer*);
+ static Type* JSTypeOfTyper(Type*, Typer*);
static Type* JSLoadPropertyTyper(Type*, Type*, Typer*);
static Type* JSCallFunctionTyper(Type*, Typer*);
- Reduction UpdateBounds(Node* node, Bounds current) {
+ static Type* ReferenceEqualTyper(Type*, Type*, Typer*);
+
+ Reduction UpdateType(Node* node, Type* current) {
if (NodeProperties::IsTyped(node)) {
- // Widen the bounds of a previously typed node.
- Bounds previous = NodeProperties::GetBounds(node);
- // Speed up termination in the presence of range types:
- current.upper = Weaken(current.upper, previous.upper);
- current.lower = Weaken(current.lower, previous.lower);
+ // Widen the type of a previously typed node.
+ Type* previous = NodeProperties::GetType(node);
+ if (node->opcode() == IrOpcode::kPhi) {
+ // Speed up termination in the presence of range types:
+ current = Weaken(node, current, previous);
+ }
- // Types should not get less precise.
- DCHECK(previous.lower->Is(current.lower));
- DCHECK(previous.upper->Is(current.upper));
+ CHECK(previous->Is(current));
- NodeProperties::SetBounds(node, current);
- if (!(previous.Narrows(current) && current.Narrows(previous))) {
+ NodeProperties::SetType(node, current);
+ if (!current->Is(previous)) {
// If something changed, revisit all uses.
return Changed(node);
}
return NoChange();
} else {
- // No previous type, simply update the bounds.
- NodeProperties::SetBounds(node, current);
+ // No previous type, simply update the type.
+ NodeProperties::SetType(node, current);
return Changed(node);
}
}
};
-void Typer::Run() {
- {
- // TODO(titzer): this is a hack. Reset types for interior nodes first.
- NodeDeque deque(zone());
- NodeMarker<bool> marked(graph(), 2);
- deque.push_front(graph()->end());
- marked.Set(graph()->end(), true);
- while (!deque.empty()) {
- Node* node = deque.front();
- deque.pop_front();
- // TODO(titzer): there shouldn't be a need to retype constants.
- if (node->op()->ValueOutputCount() > 0)
- NodeProperties::RemoveBounds(node);
- for (Node* input : node->inputs()) {
- if (!marked.Get(input)) {
- marked.Set(input, true);
- deque.push_back(input);
- }
- }
- }
- }
+void Typer::Run() { Run(NodeVector(zone())); }
+
+void Typer::Run(const NodeVector& roots) {
Visitor visitor(this);
- GraphReducer graph_reducer(graph(), zone());
+ GraphReducer graph_reducer(zone(), graph());
graph_reducer.AddReducer(&visitor);
+ for (Node* const root : roots) graph_reducer.ReduceNode(root);
graph_reducer.ReduceGraph();
}
@@ -424,12 +306,12 @@
bool is_typed = NodeProperties::IsTyped(node);
if (is_typed || NodeProperties::AllValueInputsAreTyped(node)) {
Visitor typing(typer_);
- Bounds bounds = typing.TypeNode(node);
+ Type* type = typing.TypeNode(node);
if (is_typed) {
- bounds =
- Bounds::Both(bounds, NodeProperties::GetBounds(node), typer_->zone());
+ type = Type::Intersect(type, NodeProperties::GetType(node),
+ typer_->zone());
}
- NodeProperties::SetBounds(node, bounds);
+ NodeProperties::SetType(node, type);
}
}
}
@@ -442,54 +324,54 @@
// as an argument.
-Bounds Typer::Visitor::TypeUnaryOp(Node* node, UnaryTyperFun f) {
- Bounds input = Operand(node, 0);
- Type* upper = input.upper->Is(Type::None())
- ? Type::None()
- : f(input.upper, typer_);
- Type* lower = input.lower->Is(Type::None())
- ? Type::None()
- : (input.lower == input.upper || upper->IsConstant())
- ? upper // TODO(neis): Extend this to Range(x,x), NaN, MinusZero, ...?
- : f(input.lower, typer_);
- // TODO(neis): Figure out what to do with lower bound.
- return Bounds(lower, upper);
+Type* Typer::Visitor::TypeUnaryOp(Node* node, UnaryTyperFun f) {
+ Type* input = Operand(node, 0);
+ return input->IsInhabited() ? f(input, typer_) : Type::None();
}
-Bounds Typer::Visitor::TypeBinaryOp(Node* node, BinaryTyperFun f) {
- Bounds left = Operand(node, 0);
- Bounds right = Operand(node, 1);
- Type* upper = left.upper->Is(Type::None()) || right.upper->Is(Type::None())
- ? Type::None()
- : f(left.upper, right.upper, typer_);
- Type* lower = left.lower->Is(Type::None()) || right.lower->Is(Type::None())
- ? Type::None()
- : ((left.lower == left.upper && right.lower == right.upper) ||
- upper->IsConstant())
- ? upper
- : f(left.lower, right.lower, typer_);
- // TODO(neis): Figure out what to do with lower bound.
- return Bounds(lower, upper);
+Type* Typer::Visitor::TypeBinaryOp(Node* node, BinaryTyperFun f) {
+ Type* left = Operand(node, 0);
+ Type* right = Operand(node, 1);
+ return left->IsInhabited() && right->IsInhabited() ? f(left, right, typer_)
+ : Type::None();
}
Type* Typer::Visitor::Invert(Type* type, Typer* t) {
- if (type->Is(t->singleton_false)) return t->singleton_true;
- if (type->Is(t->singleton_true)) return t->singleton_false;
+ DCHECK(type->Is(Type::Boolean()));
+ DCHECK(type->IsInhabited());
+ if (type->Is(t->singleton_false_)) return t->singleton_true_;
+ if (type->Is(t->singleton_true_)) return t->singleton_false_;
return type;
}
-Type* Typer::Visitor::FalsifyUndefined(Type* type, Typer* t) {
- if (type->Is(Type::Undefined())) return t->singleton_false;
- return type;
+Typer::Visitor::ComparisonOutcome Typer::Visitor::Invert(
+ ComparisonOutcome outcome, Typer* t) {
+ ComparisonOutcome result(0);
+ if ((outcome & kComparisonUndefined) != 0) result |= kComparisonUndefined;
+ if ((outcome & kComparisonTrue) != 0) result |= kComparisonFalse;
+ if ((outcome & kComparisonFalse) != 0) result |= kComparisonTrue;
+ return result;
+}
+
+
+Type* Typer::Visitor::FalsifyUndefined(ComparisonOutcome outcome, Typer* t) {
+ if ((outcome & kComparisonFalse) != 0 ||
+ (outcome & kComparisonUndefined) != 0) {
+ return (outcome & kComparisonTrue) != 0 ? Type::Boolean()
+ : t->singleton_false_;
+ }
+ // Type should be non empty, so we know it should be true.
+ DCHECK((outcome & kComparisonTrue) != 0);
+ return t->singleton_true_;
}
Type* Typer::Visitor::Rangify(Type* type, Typer* t) {
if (type->IsRange()) return type; // Shortcut.
- if (!type->Is(t->integer) && !type->Is(Type::Integral32())) {
+ if (!type->Is(t->cache_.kInteger)) {
return type; // Give up on non-integer types.
}
double min = type->Min();
@@ -500,8 +382,7 @@
DCHECK(std::isnan(max));
return type;
}
- Factory* f = t->isolate()->factory();
- return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
+ return Type::Range(min, max, t->zone());
}
@@ -518,38 +399,84 @@
Type* Typer::Visitor::ToBoolean(Type* type, Typer* t) {
if (type->Is(Type::Boolean())) return type;
- if (type->Is(t->falsish)) return t->singleton_false;
- if (type->Is(t->truish)) return t->singleton_true;
+ if (type->Is(t->falsish_)) return t->singleton_false_;
+ if (type->Is(t->truish_)) return t->singleton_true_;
if (type->Is(Type::PlainNumber()) && (type->Max() < 0 || 0 < type->Min())) {
- return t->singleton_true; // Ruled out nan, -0 and +0.
+ return t->singleton_true_; // Ruled out nan, -0 and +0.
}
return Type::Boolean();
}
+// static
+Type* Typer::Visitor::ToInteger(Type* type, Typer* t) {
+ // ES6 section 7.1.4 ToInteger ( argument )
+ type = ToNumber(type, t);
+ if (type->Is(t->cache_.kIntegerOrMinusZero)) return type;
+ return t->cache_.kIntegerOrMinusZero;
+}
+
+
+// static
+Type* Typer::Visitor::ToLength(Type* type, Typer* t) {
+ // ES6 section 7.1.15 ToLength ( argument )
+ type = ToInteger(type, t);
+ double min = type->Min();
+ double max = type->Max();
+ if (min <= 0.0) min = 0.0;
+ if (max > kMaxSafeInteger) max = kMaxSafeInteger;
+ if (max <= min) max = min;
+ return Type::Range(min, max, t->zone());
+}
+
+
+// static
+Type* Typer::Visitor::ToName(Type* type, Typer* t) {
+ // ES6 section 7.1.14 ToPropertyKey ( argument )
+ type = ToPrimitive(type, t);
+ if (type->Is(Type::Name())) return type;
+ if (type->Maybe(Type::Symbol())) return Type::Name();
+ return ToString(type, t);
+}
+
+
+// static
Type* Typer::Visitor::ToNumber(Type* type, Typer* t) {
if (type->Is(Type::Number())) return type;
- if (type->Is(Type::Null())) return t->singleton_zero;
- if (type->Is(Type::Undefined())) return Type::NaN();
- if (type->Is(t->undefined_or_null)) {
- return Type::Union(Type::NaN(), t->singleton_zero, t->zone());
+ if (type->Is(Type::NullOrUndefined())) {
+ if (type->Is(Type::Null())) return t->cache_.kSingletonZero;
+ if (type->Is(Type::Undefined())) return Type::NaN();
+ return Type::Union(Type::NaN(), t->cache_.kSingletonZero, t->zone());
}
- if (type->Is(t->undefined_or_number)) {
+ if (type->Is(Type::NumberOrUndefined())) {
return Type::Union(Type::Intersect(type, Type::Number(), t->zone()),
Type::NaN(), t->zone());
}
- if (type->Is(t->singleton_false)) return t->singleton_zero;
- if (type->Is(t->singleton_true)) return t->singleton_one;
- if (type->Is(Type::Boolean())) return t->zero_or_one;
- if (type->Is(t->boolean_or_number)) {
+ if (type->Is(t->singleton_false_)) return t->cache_.kSingletonZero;
+ if (type->Is(t->singleton_true_)) return t->cache_.kSingletonOne;
+ if (type->Is(Type::Boolean())) return t->cache_.kZeroOrOne;
+ if (type->Is(Type::BooleanOrNumber())) {
return Type::Union(Type::Intersect(type, Type::Number(), t->zone()),
- t->zero_or_one, t->zone());
+ t->cache_.kZeroOrOne, t->zone());
}
return Type::Number();
}
+// static
+Type* Typer::Visitor::ToObject(Type* type, Typer* t) {
+ // ES6 section 7.1.13 ToObject ( argument )
+ if (type->Is(Type::Receiver())) return type;
+ if (type->Is(Type::Primitive())) return Type::OtherObject();
+ if (!type->Maybe(Type::Undetectable())) return Type::DetectableReceiver();
+ return Type::Receiver();
+}
+
+
+// static
Type* Typer::Visitor::ToString(Type* type, Typer* t) {
+ // ES6 section 7.1.12 ToString ( argument )
+ type = ToPrimitive(type, t);
if (type->Is(Type::String())) return type;
return Type::String();
}
@@ -558,10 +485,11 @@
Type* Typer::Visitor::NumberToInt32(Type* type, Typer* t) {
// TODO(neis): DCHECK(type->Is(Type::Number()));
if (type->Is(Type::Signed32())) return type;
- if (type->Is(t->zeroish)) return t->singleton_zero;
- if (type->Is(t->signed32ish)) {
- return Type::Intersect(Type::Union(type, t->singleton_zero, t->zone()),
- Type::Signed32(), t->zone());
+ if (type->Is(t->cache_.kZeroish)) return t->cache_.kSingletonZero;
+ if (type->Is(t->signed32ish_)) {
+ return Type::Intersect(
+ Type::Union(type, t->cache_.kSingletonZero, t->zone()),
+ Type::Signed32(), t->zone());
}
return Type::Signed32();
}
@@ -570,10 +498,11 @@
Type* Typer::Visitor::NumberToUint32(Type* type, Typer* t) {
// TODO(neis): DCHECK(type->Is(Type::Number()));
if (type->Is(Type::Unsigned32())) return type;
- if (type->Is(t->zeroish)) return t->singleton_zero;
- if (type->Is(t->unsigned32ish)) {
- return Type::Intersect(Type::Union(type, t->singleton_zero, t->zone()),
- Type::Unsigned32(), t->zone());
+ if (type->Is(t->cache_.kZeroish)) return t->cache_.kSingletonZero;
+ if (type->Is(t->unsigned32ish_)) {
+ return Type::Intersect(
+ Type::Union(type, t->cache_.kSingletonZero, t->zone()),
+ Type::Unsigned32(), t->zone());
}
return Type::Unsigned32();
}
@@ -585,135 +514,167 @@
// Control operators.
-Bounds Typer::Visitor::TypeStart(Node* node) {
- return Bounds(Type::None(zone()), Type::Internal(zone()));
-}
+Type* Typer::Visitor::TypeStart(Node* node) { return Type::Internal(zone()); }
+
+
+Type* Typer::Visitor::TypeIfException(Node* node) { return Type::Any(); }
// Common operators.
-Bounds Typer::Visitor::TypeParameter(Node* node) {
- return Bounds::Unbounded(zone());
-}
-
-
-Bounds Typer::Visitor::TypeInt32Constant(Node* node) {
- Factory* f = isolate()->factory();
- Handle<Object> number = f->NewNumber(OpParameter<int32_t>(node));
- return Bounds(Type::Intersect(
- Type::Range(number, number, zone()), Type::UntaggedSigned32(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeInt64Constant(Node* node) {
- // TODO(rossberg): This actually seems to be a PointerConstant so far...
- return Bounds(Type::Internal()); // TODO(rossberg): Add int64 bitset type?
-}
-
-
-Bounds Typer::Visitor::TypeFloat32Constant(Node* node) {
- return Bounds(Type::Intersect(
- Type::Of(OpParameter<float>(node), zone()),
- Type::UntaggedFloat32(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeFloat64Constant(Node* node) {
- return Bounds(Type::Intersect(
- Type::Of(OpParameter<double>(node), zone()),
- Type::UntaggedFloat64(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeNumberConstant(Node* node) {
- Factory* f = isolate()->factory();
- return Bounds(Type::Constant(
- f->NewNumber(OpParameter<double>(node)), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeHeapConstant(Node* node) {
- return Bounds(TypeConstant(OpParameter<Unique<HeapObject> >(node).handle()));
-}
-
-
-Bounds Typer::Visitor::TypeExternalConstant(Node* node) {
- return Bounds(Type::None(zone()), Type::Internal(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeSelect(Node* node) {
- return Bounds::Either(Operand(node, 1), Operand(node, 2), zone());
-}
-
-
-Bounds Typer::Visitor::TypePhi(Node* node) {
- int arity = node->op()->ValueInputCount();
- Bounds bounds = Operand(node, 0);
- for (int i = 1; i < arity; ++i) {
- bounds = Bounds::Either(bounds, Operand(node, i), zone());
+Type* Typer::Visitor::TypeParameter(Node* node) {
+ if (Type::FunctionType* function_type = typer_->function_type()) {
+ int const index = ParameterIndexOf(node->op());
+ if (index >= 0 && index < function_type->Arity()) {
+ return function_type->Parameter(index);
+ }
}
- return bounds;
+ return Type::Any();
}
-Bounds Typer::Visitor::TypeEffectPhi(Node* node) {
+Type* Typer::Visitor::TypeOsrValue(Node* node) { return Type::Any(); }
+
+
+Type* Typer::Visitor::TypeInt32Constant(Node* node) {
+ double number = OpParameter<int32_t>(node);
+ return Type::Intersect(Type::Range(number, number, zone()),
+ Type::UntaggedIntegral32(), zone());
+}
+
+
+Type* Typer::Visitor::TypeInt64Constant(Node* node) {
+ // TODO(rossberg): This actually seems to be a PointerConstant so far...
+ return Type::Internal(); // TODO(rossberg): Add int64 bitset type?
+}
+
+
+Type* Typer::Visitor::TypeFloat32Constant(Node* node) {
+ return Type::Intersect(Type::Of(OpParameter<float>(node), zone()),
+ Type::UntaggedFloat32(), zone());
+}
+
+
+Type* Typer::Visitor::TypeFloat64Constant(Node* node) {
+ return Type::Intersect(Type::Of(OpParameter<double>(node), zone()),
+ Type::UntaggedFloat64(), zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberConstant(Node* node) {
+ Factory* f = isolate()->factory();
+ double number = OpParameter<double>(node);
+ if (Type::IsInteger(number)) {
+ return Type::Range(number, number, zone());
+ }
+ return Type::Constant(f->NewNumber(number), zone());
+}
+
+
+Type* Typer::Visitor::TypeHeapConstant(Node* node) {
+ return TypeConstant(OpParameter<Handle<HeapObject>>(node));
+}
+
+
+Type* Typer::Visitor::TypeExternalConstant(Node* node) {
+ return Type::Internal(zone());
+}
+
+
+Type* Typer::Visitor::TypeSelect(Node* node) {
+ return Type::Union(Operand(node, 1), Operand(node, 2), zone());
+}
+
+
+Type* Typer::Visitor::TypePhi(Node* node) {
+ int arity = node->op()->ValueInputCount();
+ Type* type = Operand(node, 0);
+ for (int i = 1; i < arity; ++i) {
+ type = Type::Union(type, Operand(node, i), zone());
+ }
+ return type;
+}
+
+
+Type* Typer::Visitor::TypeEffectPhi(Node* node) {
UNREACHABLE();
- return Bounds();
+ return nullptr;
}
-Bounds Typer::Visitor::TypeValueEffect(Node* node) {
+Type* Typer::Visitor::TypeEffectSet(Node* node) {
UNREACHABLE();
- return Bounds();
+ return nullptr;
}
-Bounds Typer::Visitor::TypeFinish(Node* node) {
- return Operand(node, 0);
+Type* Typer::Visitor::TypeGuard(Node* node) {
+ Type* input_type = Operand(node, 0);
+ Type* guard_type = OpParameter<Type*>(node);
+ return Type::Intersect(input_type, guard_type, zone());
}
-Bounds Typer::Visitor::TypeFrameState(Node* node) {
+Type* Typer::Visitor::TypeBeginRegion(Node* node) {
+ UNREACHABLE();
+ return nullptr;
+}
+
+
+Type* Typer::Visitor::TypeFinishRegion(Node* node) { return Operand(node, 0); }
+
+
+Type* Typer::Visitor::TypeFrameState(Node* node) {
// TODO(rossberg): Ideally FrameState wouldn't have a value output.
- return Bounds(Type::None(zone()), Type::Internal(zone()));
+ return Type::Internal(zone());
}
-Bounds Typer::Visitor::TypeStateValues(Node* node) {
- return Bounds(Type::None(zone()), Type::Internal(zone()));
+Type* Typer::Visitor::TypeStateValues(Node* node) {
+ return Type::Internal(zone());
}
-Bounds Typer::Visitor::TypeCall(Node* node) {
- return Bounds::Unbounded(zone());
+Type* Typer::Visitor::TypeObjectState(Node* node) {
+ return Type::Internal(zone());
}
-Bounds Typer::Visitor::TypeProjection(Node* node) {
+Type* Typer::Visitor::TypeTypedStateValues(Node* node) {
+ return Type::Internal(zone());
+}
+
+
+Type* Typer::Visitor::TypeCall(Node* node) { return Type::Any(); }
+
+
+Type* Typer::Visitor::TypeProjection(Node* node) {
// TODO(titzer): use the output type of the input to determine the bounds.
- return Bounds::Unbounded(zone());
+ return Type::Any();
}
+Type* Typer::Visitor::TypeDead(Node* node) { return Type::Any(); }
+
+
// JS comparison operators.
Type* Typer::Visitor::JSEqualTyper(Type* lhs, Type* rhs, Typer* t) {
- if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false;
- if (lhs->Is(t->undefined_or_null) && rhs->Is(t->undefined_or_null)) {
- return t->singleton_true;
+ if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false_;
+ if (lhs->Is(Type::NullOrUndefined()) && rhs->Is(Type::NullOrUndefined())) {
+ return t->singleton_true_;
}
if (lhs->Is(Type::Number()) && rhs->Is(Type::Number()) &&
(lhs->Max() < rhs->Min() || lhs->Min() > rhs->Max())) {
- return t->singleton_false;
+ return t->singleton_false_;
}
if (lhs->IsConstant() && rhs->Is(lhs)) {
// Types are equal and are inhabited only by a single semantic value,
// which is not nan due to the earlier check.
// TODO(neis): Extend this to Range(x,x), MinusZero, ...?
- return t->singleton_true;
+ return t->singleton_true_;
}
return Type::Boolean();
}
@@ -737,16 +698,20 @@
Type* Typer::Visitor::JSStrictEqualTyper(Type* lhs, Type* rhs, Typer* t) {
- if (!JSType(lhs)->Maybe(JSType(rhs))) return t->singleton_false;
- if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false;
+ if (!JSType(lhs)->Maybe(JSType(rhs))) return t->singleton_false_;
+ if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false_;
if (lhs->Is(Type::Number()) && rhs->Is(Type::Number()) &&
(lhs->Max() < rhs->Min() || lhs->Min() > rhs->Max())) {
- return t->singleton_false;
+ return t->singleton_false_;
+ }
+ if ((lhs->Is(t->singleton_the_hole_) || rhs->Is(t->singleton_the_hole_)) &&
+ !lhs->Maybe(rhs)) {
+ return t->singleton_false_;
}
if (lhs->IsConstant() && 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;
+ return t->singleton_true_;
}
return Type::Boolean();
}
@@ -761,26 +726,41 @@
// (<, <=, >=, >) with the help of a single abstract one. It behaves like <
// but returns undefined when the inputs cannot be compared.
// We implement the typing analogously.
-Type* Typer::Visitor::JSCompareTyper(Type* lhs, Type* rhs, Typer* t) {
+Typer::Visitor::ComparisonOutcome Typer::Visitor::JSCompareTyper(Type* lhs,
+ Type* rhs,
+ Typer* t) {
lhs = ToPrimitive(lhs, t);
rhs = ToPrimitive(rhs, t);
if (lhs->Maybe(Type::String()) && rhs->Maybe(Type::String())) {
- return Type::Boolean();
+ return ComparisonOutcome(kComparisonTrue) |
+ ComparisonOutcome(kComparisonFalse);
}
lhs = ToNumber(lhs, t);
rhs = ToNumber(rhs, t);
- if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::Undefined();
+
+ // Shortcut for NaNs.
+ if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return kComparisonUndefined;
+
+ ComparisonOutcome result;
if (lhs->IsConstant() && rhs->Is(lhs)) {
- // Types are equal and are inhabited only by a single semantic value,
- // which is not NaN due to the previous check.
- return t->singleton_false;
+ // Types are equal and are inhabited only by a single semantic value.
+ result = kComparisonFalse;
+ } else if (lhs->Min() >= rhs->Max()) {
+ result = kComparisonFalse;
+ } else if (lhs->Max() < rhs->Min()) {
+ result = kComparisonTrue;
+ } else {
+ // We cannot figure out the result, return both true and false. (We do not
+ // have to return undefined because that cannot affect the result of
+ // FalsifyUndefined.)
+ return ComparisonOutcome(kComparisonTrue) |
+ ComparisonOutcome(kComparisonFalse);
}
- if (lhs->Min() >= rhs->Max()) return t->singleton_false;
- if (lhs->Max() < rhs->Min() &&
- !lhs->Maybe(Type::NaN()) && !rhs->Maybe(Type::NaN())) {
- return t->singleton_true;
+ // Add the undefined if we could see NaN.
+ if (lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN())) {
+ result |= kComparisonUndefined;
}
- return Type::Boolean();
+ return result;
}
@@ -809,7 +789,6 @@
Type* Typer::Visitor::JSBitwiseOrTyper(Type* lhs, Type* rhs, Typer* t) {
- Factory* f = t->isolate()->factory();
lhs = NumberToInt32(ToNumber(lhs, t), t);
rhs = NumberToInt32(ToNumber(rhs, t), t);
double lmin = lhs->Min();
@@ -837,13 +816,12 @@
// value.
max = std::min(max, -1.0);
}
- return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
+ return Type::Range(min, max, t->zone());
// TODO(neis): Be precise for singleton inputs, here and elsewhere.
}
Type* Typer::Visitor::JSBitwiseAndTyper(Type* lhs, Type* rhs, Typer* t) {
- Factory* f = t->isolate()->factory();
lhs = NumberToInt32(ToNumber(lhs, t), t);
rhs = NumberToInt32(ToNumber(rhs, t), t);
double lmin = lhs->Min();
@@ -865,7 +843,7 @@
min = 0;
max = std::min(max, rmax);
}
- return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
+ return Type::Range(min, max, t->zone());
}
@@ -878,12 +856,12 @@
double rmax = rhs->Max();
if ((lmin >= 0 && rmin >= 0) || (lmax < 0 && rmax < 0)) {
// Xor-ing negative or non-negative values results in a non-negative value.
- return Type::NonNegativeSigned32();
+ return Type::Unsigned31();
}
if ((lmax < 0 && rmin >= 0) || (lmin >= 0 && rmax < 0)) {
// Xor-ing a negative and a non-negative value results in a negative value.
// TODO(jarin) Use a range here.
- return Type::NegativeSigned32();
+ return Type::Negative32();
}
return Type::Signed32();
}
@@ -903,11 +881,17 @@
// Right-shifting a non-negative value cannot make it negative, nor larger.
min = std::max(min, 0.0);
max = std::min(max, lhs->Max());
+ if (rhs->Min() > 0 && rhs->Max() <= 31) {
+ max = static_cast<int>(max) >> static_cast<int>(rhs->Min());
+ }
}
if (lhs->Max() < 0) {
// Right-shifting a negative value cannot make it non-negative, nor smaller.
min = std::max(min, lhs->Min());
max = std::min(max, -1.0);
+ if (rhs->Min() > 0 && rhs->Max() <= 31) {
+ min = static_cast<int>(min) >> static_cast<int>(rhs->Min());
+ }
}
if (rhs->Min() > 0 && rhs->Max() <= 31) {
// Right-shifting by a positive value yields a small integer value.
@@ -919,8 +903,7 @@
// TODO(jarin) Ideally, the following micro-optimization should be performed
// by the type constructor.
if (max != Type::Signed32()->Max() || min != Type::Signed32()->Min()) {
- Factory* f = t->isolate()->factory();
- return Type::Range(f->NewNumber(min), f->NewNumber(max), t->zone());
+ return Type::Range(min, max, t->zone());
}
return Type::Signed32();
}
@@ -928,11 +911,8 @@
Type* Typer::Visitor::JSShiftRightLogicalTyper(Type* lhs, Type* rhs, Typer* t) {
lhs = NumberToUint32(ToNumber(lhs, t), t);
- Factory* f = t->isolate()->factory();
// Logical right-shifting any value cannot make it larger.
- Handle<Object> min = f->NewNumber(0);
- Handle<Object> max = f->NewNumber(lhs->Max());
- return Type::Range(min, max, t->zone());
+ return Type::Range(0.0, lhs->Max(), t->zone());
}
@@ -974,10 +954,10 @@
Type* Typer::Visitor::JSAddRanger(Type::RangeType* lhs, Type::RangeType* rhs,
Typer* t) {
double results[4];
- results[0] = lhs->Min()->Number() + rhs->Min()->Number();
- results[1] = lhs->Min()->Number() + rhs->Max()->Number();
- results[2] = lhs->Max()->Number() + rhs->Min()->Number();
- results[3] = lhs->Max()->Number() + rhs->Max()->Number();
+ results[0] = lhs->Min() + rhs->Min();
+ results[1] = lhs->Min() + rhs->Max();
+ results[2] = lhs->Max() + rhs->Min();
+ results[3] = lhs->Max() + rhs->Max();
// Since none of the inputs can be -0, the result cannot be -0 either.
// However, it can be nan (the sum of two infinities of opposite sign).
// On the other hand, if none of the "results" above is nan, then the actual
@@ -987,9 +967,8 @@
if (std::isnan(results[i])) ++nans;
}
if (nans == 4) return Type::NaN(); // [-inf..-inf] + [inf..inf] or vice versa
- Factory* f = t->isolate()->factory();
- Type* range = Type::Range(f->NewNumber(array_min(results, 4)),
- f->NewNumber(array_max(results, 4)), t->zone());
+ Type* range =
+ Type::Range(array_min(results, 4), array_max(results, 4), t->zone());
return nans == 0 ? range : Type::Union(range, Type::NaN(), t->zone());
// Examples:
// [-inf, -inf] + [+inf, +inf] = NaN
@@ -1023,10 +1002,10 @@
Type* Typer::Visitor::JSSubtractRanger(Type::RangeType* lhs,
Type::RangeType* rhs, Typer* t) {
double results[4];
- results[0] = lhs->Min()->Number() - rhs->Min()->Number();
- results[1] = lhs->Min()->Number() - rhs->Max()->Number();
- results[2] = lhs->Max()->Number() - rhs->Min()->Number();
- results[3] = lhs->Max()->Number() - rhs->Max()->Number();
+ results[0] = lhs->Min() - rhs->Min();
+ results[1] = lhs->Min() - rhs->Max();
+ results[2] = lhs->Max() - rhs->Min();
+ results[3] = lhs->Max() - rhs->Max();
// Since none of the inputs can be -0, the result cannot be -0.
// However, it can be nan (the subtraction of two infinities of same sign).
// On the other hand, if none of the "results" above is nan, then the actual
@@ -1036,9 +1015,8 @@
if (std::isnan(results[i])) ++nans;
}
if (nans == 4) return Type::NaN(); // [inf..inf] - [inf..inf] (all same sign)
- Factory* f = t->isolate()->factory();
- Type* range = Type::Range(f->NewNumber(array_min(results, 4)),
- f->NewNumber(array_max(results, 4)), t->zone());
+ Type* range =
+ Type::Range(array_min(results, 4), array_max(results, 4), t->zone());
return nans == 0 ? range : Type::Union(range, Type::NaN(), t->zone());
// Examples:
// [-inf, +inf] - [-inf, +inf] = [-inf, +inf] \/ NaN
@@ -1062,10 +1040,10 @@
Type* Typer::Visitor::JSMultiplyRanger(Type::RangeType* lhs,
Type::RangeType* rhs, Typer* t) {
double results[4];
- double lmin = lhs->Min()->Number();
- double lmax = lhs->Max()->Number();
- double rmin = rhs->Min()->Number();
- double rmax = rhs->Max()->Number();
+ double lmin = lhs->Min();
+ double lmax = lhs->Max();
+ double rmin = rhs->Min();
+ double rmax = rhs->Max();
results[0] = lmin * rmin;
results[1] = lmin * rmax;
results[2] = lmax * rmin;
@@ -1074,16 +1052,15 @@
// the discontinuity makes it too complicated. Note that even if none of the
// "results" above is nan, the actual result may still be, so we have to do a
// different check:
- bool maybe_nan = (lhs->Maybe(t->singleton_zero) &&
+ bool maybe_nan = (lhs->Maybe(t->cache_.kSingletonZero) &&
(rmin == -V8_INFINITY || rmax == +V8_INFINITY)) ||
- (rhs->Maybe(t->singleton_zero) &&
+ (rhs->Maybe(t->cache_.kSingletonZero) &&
(lmin == -V8_INFINITY || lmax == +V8_INFINITY));
- if (maybe_nan) return t->weakint; // Giving up.
- bool maybe_minuszero = (lhs->Maybe(t->singleton_zero) && rmin < 0) ||
- (rhs->Maybe(t->singleton_zero) && lmin < 0);
- Factory* f = t->isolate()->factory();
- Type* range = Type::Range(f->NewNumber(array_min(results, 4)),
- f->NewNumber(array_max(results, 4)), t->zone());
+ if (maybe_nan) return t->cache_.kIntegerOrMinusZeroOrNaN; // Giving up.
+ bool maybe_minuszero = (lhs->Maybe(t->cache_.kSingletonZero) && rmin < 0) ||
+ (rhs->Maybe(t->cache_.kSingletonZero) && lmin < 0);
+ Type* range =
+ Type::Range(array_min(results, 4), array_max(results, 4), t->zone());
return maybe_minuszero ? Type::Union(range, Type::MinusZero(), t->zone())
: range;
}
@@ -1107,7 +1084,7 @@
// Division is tricky, so all we do is try ruling out nan.
// TODO(neis): try ruling out -0 as well?
bool maybe_nan =
- lhs->Maybe(Type::NaN()) || rhs->Maybe(t->zeroish) ||
+ lhs->Maybe(Type::NaN()) || rhs->Maybe(t->cache_.kZeroish) ||
((lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) &&
(rhs->Min() == -V8_INFINITY || rhs->Max() == +V8_INFINITY));
return maybe_nan ? Type::Number() : Type::OrderedNumber();
@@ -1116,10 +1093,10 @@
Type* Typer::Visitor::JSModulusRanger(Type::RangeType* lhs,
Type::RangeType* rhs, Typer* t) {
- double lmin = lhs->Min()->Number();
- double lmax = lhs->Max()->Number();
- double rmin = rhs->Min()->Number();
- double rmax = rhs->Max()->Number();
+ double lmin = lhs->Min();
+ double lmax = lhs->Max();
+ double rmin = rhs->Min();
+ double rmax = rhs->Max();
double labs = std::max(std::abs(lmin), std::abs(lmax));
double rabs = std::max(std::abs(rmin), std::abs(rmax)) - 1;
@@ -1140,8 +1117,7 @@
maybe_minus_zero = true;
}
- Factory* f = t->isolate()->factory();
- Type* result = Type::Range(f->NewNumber(omin), f->NewNumber(omax), t->zone());
+ Type* result = Type::Range(omin, omax, t->zone());
if (maybe_minus_zero)
result = Type::Union(result, Type::MinusZero(), t->zone());
return result;
@@ -1153,7 +1129,7 @@
rhs = ToNumber(rhs, t);
if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
- if (lhs->Maybe(Type::NaN()) || rhs->Maybe(t->zeroish) ||
+ if (lhs->Maybe(Type::NaN()) || rhs->Maybe(t->cache_.kZeroish) ||
lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) {
// Result maybe NaN.
return Type::Number();
@@ -1171,54 +1147,102 @@
// JS unary operators.
-Type* Typer::Visitor::JSUnaryNotTyper(Type* type, Typer* t) {
- return Invert(ToBoolean(type, t), 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());
+ } else if (type->Is(Type::Number())) {
+ return Type::Constant(f->number_string(), t->zone());
+ } else if (type->Is(Type::String())) {
+ return Type::Constant(f->string_string(), t->zone());
+ } else if (type->Is(Type::Symbol())) {
+ return Type::Constant(f->symbol_string(), t->zone());
+ } else if (type->Is(Type::Union(Type::Undefined(), Type::Undetectable(),
+ t->zone()))) {
+ return Type::Constant(f->undefined_string(), t->zone());
+ } else if (type->Is(Type::Null())) {
+ return Type::Constant(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::InternalizedString();
}
-Bounds Typer::Visitor::TypeJSUnaryNot(Node* node) {
- return TypeUnaryOp(node, JSUnaryNotTyper);
-}
-
-
-Bounds Typer::Visitor::TypeJSTypeOf(Node* node) {
- return Bounds(Type::None(zone()), Type::InternalizedString(zone()));
+Type* Typer::Visitor::TypeJSTypeOf(Node* node) {
+ return TypeUnaryOp(node, JSTypeOfTyper);
}
// JS conversion operators.
-Bounds Typer::Visitor::TypeJSToBoolean(Node* node) {
+Type* Typer::Visitor::TypeJSToBoolean(Node* node) {
return TypeUnaryOp(node, ToBoolean);
}
-Bounds Typer::Visitor::TypeJSToNumber(Node* node) {
+Type* Typer::Visitor::TypeJSToNumber(Node* node) {
return TypeUnaryOp(node, ToNumber);
}
-Bounds Typer::Visitor::TypeJSToString(Node* node) {
+Type* Typer::Visitor::TypeJSToString(Node* node) {
return TypeUnaryOp(node, ToString);
}
-Bounds Typer::Visitor::TypeJSToName(Node* node) {
- return Bounds(Type::None(), Type::Name());
+Type* Typer::Visitor::TypeJSToName(Node* node) {
+ return TypeUnaryOp(node, ToName);
}
-Bounds Typer::Visitor::TypeJSToObject(Node* node) {
- return Bounds(Type::None(), Type::Receiver());
+Type* Typer::Visitor::TypeJSToObject(Node* node) {
+ return TypeUnaryOp(node, ToObject);
}
// JS object operators.
-Bounds Typer::Visitor::TypeJSCreate(Node* node) {
- return Bounds(Type::None(), Type::Object());
+Type* Typer::Visitor::TypeJSCreate(Node* node) { return Type::Object(); }
+
+
+Type* Typer::Visitor::TypeJSCreateArguments(Node* node) {
+ return Type::OtherObject();
+}
+
+
+Type* Typer::Visitor::TypeJSCreateArray(Node* node) {
+ return Type::OtherObject();
+}
+
+
+Type* Typer::Visitor::TypeJSCreateClosure(Node* node) {
+ return Type::Function();
+}
+
+
+Type* Typer::Visitor::TypeJSCreateIterResultObject(Node* node) {
+ return Type::OtherObject();
+}
+
+
+Type* Typer::Visitor::TypeJSCreateLiteralArray(Node* node) {
+ return Type::OtherObject();
+}
+
+
+Type* Typer::Visitor::TypeJSCreateLiteralObject(Node* node) {
+ return Type::OtherObject();
+}
+
+
+Type* Typer::Visitor::TypeJSCreateLiteralRegExp(Node* node) {
+ return Type::OtherObject();
}
@@ -1232,819 +1256,253 @@
}
-Bounds Typer::Visitor::TypeJSLoadProperty(Node* node) {
+Type* Typer::Visitor::TypeJSLoadProperty(Node* node) {
return TypeBinaryOp(node, JSLoadPropertyTyper);
}
-Bounds Typer::Visitor::TypeJSLoadNamed(Node* node) {
- return Bounds::Unbounded(zone());
+Type* Typer::Visitor::TypeJSLoadNamed(Node* node) {
+ Factory* const f = isolate()->factory();
+ Handle<Name> name = NamedAccessOf(node->op()).name();
+ if (name.is_identical_to(f->prototype_string())) {
+ Type* receiver = Operand(node, 0);
+ if (receiver->Is(Type::None())) return Type::None();
+ if (receiver->IsConstant() &&
+ receiver->AsConstant()->Value()->IsJSFunction()) {
+ Handle<JSFunction> function =
+ Handle<JSFunction>::cast(receiver->AsConstant()->Value());
+ if (function->has_prototype()) {
+ // We need to add a code dependency on the initial map of the {function}
+ // in order to be notified about changes to "prototype" of {function},
+ // so we can only infer a constant type if deoptimization is enabled.
+ if (flags() & kDeoptimizationEnabled) {
+ JSFunction::EnsureHasInitialMap(function);
+ Handle<Map> initial_map(function->initial_map(), isolate());
+ dependencies()->AssumeInitialMapCantChange(initial_map);
+ return Type::Constant(handle(initial_map->prototype(), isolate()),
+ zone());
+ }
+ }
+ } else if (receiver->IsClass() &&
+ receiver->AsClass()->Map()->IsJSFunctionMap()) {
+ Handle<Map> map = receiver->AsClass()->Map();
+ return map->has_non_instance_prototype() ? Type::Primitive(zone())
+ : Type::Receiver(zone());
+ }
+ }
+ return Type::Any();
}
+Type* Typer::Visitor::TypeJSLoadGlobal(Node* node) { return Type::Any(); }
+
+
// Returns a somewhat larger range if we previously assigned
// a (smaller) range to this node. This is used to speed up
// the fixpoint calculation in case there appears to be a loop
// in the graph. In the current implementation, we are
// increasing the limits to the closest power of two.
-Type* Typer::Visitor::Weaken(Type* current_type, Type* previous_type) {
- Type::RangeType* previous = previous_type->GetRange();
- Type::RangeType* current = current_type->GetRange();
- if (previous != NULL && current != NULL) {
- double current_min = current->Min()->Number();
- Handle<Object> new_min = current->Min();
+Type* Typer::Visitor::Weaken(Node* node, Type* current_type,
+ Type* previous_type) {
+ static const double kWeakenMinLimits[] = {
+ 0.0, -1073741824.0, -2147483648.0, -4294967296.0, -8589934592.0,
+ -17179869184.0, -34359738368.0, -68719476736.0, -137438953472.0,
+ -274877906944.0, -549755813888.0, -1099511627776.0, -2199023255552.0,
+ -4398046511104.0, -8796093022208.0, -17592186044416.0, -35184372088832.0,
+ -70368744177664.0, -140737488355328.0, -281474976710656.0,
+ -562949953421312.0};
+ static const double kWeakenMaxLimits[] = {
+ 0.0, 1073741823.0, 2147483647.0, 4294967295.0, 8589934591.0,
+ 17179869183.0, 34359738367.0, 68719476735.0, 137438953471.0,
+ 274877906943.0, 549755813887.0, 1099511627775.0, 2199023255551.0,
+ 4398046511103.0, 8796093022207.0, 17592186044415.0, 35184372088831.0,
+ 70368744177663.0, 140737488355327.0, 281474976710655.0,
+ 562949953421311.0};
+ STATIC_ASSERT(arraysize(kWeakenMinLimits) == arraysize(kWeakenMaxLimits));
- // Find the closest lower entry in the list of allowed
- // minima (or negative infinity if there is no such entry).
- if (current_min != previous->Min()->Number()) {
- new_min = typer_->integer->AsRange()->Min();
- for (const auto val : typer_->weaken_min_limits_) {
- if (val->Number() <= current_min) {
- new_min = val;
- break;
- }
- }
- }
-
- double current_max = current->Max()->Number();
- Handle<Object> new_max = current->Max();
- // Find the closest greater entry in the list of allowed
- // maxima (or infinity if there is no such entry).
- if (current_max != previous->Max()->Number()) {
- new_max = typer_->integer->AsRange()->Max();
- for (const auto val : typer_->weaken_max_limits_) {
- if (val->Number() >= current_max) {
- new_max = val;
- break;
- }
- }
- }
-
- return Type::Union(current_type,
- Type::Range(new_min, new_max, typer_->zone()),
- typer_->zone());
+ // If the types have nothing to do with integers, return the types.
+ Type* const integer = typer_->cache_.kInteger;
+ if (!previous_type->Maybe(integer)) {
+ return current_type;
}
- return current_type;
+ DCHECK(current_type->Maybe(integer));
+
+ Type* current_integer = Type::Intersect(current_type, integer, zone());
+ Type* previous_integer = Type::Intersect(previous_type, integer, zone());
+
+ // Once we start weakening a node, we should always weaken.
+ if (!IsWeakened(node->id())) {
+ // Only weaken if there is range involved; we should converge quickly
+ // for all other types (the exception is a union of many constants,
+ // but we currently do not increase the number of constants in unions).
+ Type::RangeType* previous = previous_integer->GetRange();
+ Type::RangeType* current = current_integer->GetRange();
+ if (current == nullptr || previous == nullptr) {
+ return current_type;
+ }
+ // Range is involved => we are weakening.
+ SetWeakened(node->id());
+ }
+
+ double current_min = current_integer->Min();
+ double new_min = current_min;
+ // Find the closest lower entry in the list of allowed
+ // minima (or negative infinity if there is no such entry).
+ if (current_min != previous_integer->Min()) {
+ new_min = -V8_INFINITY;
+ for (double const min : kWeakenMinLimits) {
+ if (min <= current_min) {
+ new_min = min;
+ break;
+ }
+ }
+ }
+
+ double current_max = current_integer->Max();
+ double new_max = current_max;
+ // Find the closest greater entry in the list of allowed
+ // maxima (or infinity if there is no such entry).
+ if (current_max != previous_integer->Max()) {
+ new_max = V8_INFINITY;
+ for (double const max : kWeakenMaxLimits) {
+ if (max >= current_max) {
+ new_max = max;
+ break;
+ }
+ }
+ }
+
+ return Type::Union(current_type,
+ Type::Range(new_min, new_max, typer_->zone()),
+ typer_->zone());
}
-Bounds Typer::Visitor::TypeJSStoreProperty(Node* node) {
+Type* Typer::Visitor::TypeJSStoreProperty(Node* node) {
UNREACHABLE();
- return Bounds();
+ return nullptr;
}
-Bounds Typer::Visitor::TypeJSStoreNamed(Node* node) {
+Type* Typer::Visitor::TypeJSStoreNamed(Node* node) {
UNREACHABLE();
- return Bounds();
+ return nullptr;
}
-Bounds Typer::Visitor::TypeJSDeleteProperty(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
+Type* Typer::Visitor::TypeJSStoreGlobal(Node* node) {
+ UNREACHABLE();
+ return nullptr;
}
-Bounds Typer::Visitor::TypeJSHasProperty(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
+Type* Typer::Visitor::TypeJSDeleteProperty(Node* node) {
+ return Type::Boolean(zone());
}
-Bounds Typer::Visitor::TypeJSInstanceOf(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
+Type* Typer::Visitor::TypeJSHasProperty(Node* node) {
+ return Type::Boolean(zone());
+}
+
+
+Type* Typer::Visitor::TypeJSInstanceOf(Node* node) {
+ return Type::Boolean(zone());
}
// JS context operators.
-Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
- Bounds outer = Operand(node, 0);
- Type* context_type = outer.upper;
- if (context_type->Is(Type::None())) {
- // Upper bound of context is not yet known.
- return Bounds(Type::None(), Type::Any());
+Type* Typer::Visitor::TypeJSLoadContext(Node* node) {
+ ContextAccess const& access = ContextAccessOf(node->op());
+ if (access.index() == Context::EXTENSION_INDEX) {
+ return Type::TaggedPointer();
}
-
- DCHECK(context_type->Maybe(Type::Internal()));
- // TODO(rossberg): More precisely, instead of the above assertion, we should
- // back-propagate the constraint that it has to be a subtype of Internal.
-
- ContextAccess access = OpParameter<ContextAccess>(node);
- MaybeHandle<Context> context;
- if (context_type->IsConstant()) {
- context = Handle<Context>::cast(context_type->AsConstant()->Value());
- }
- // Walk context chain (as far as known), mirroring dynamic lookup.
- // Since contexts are mutable, the information is only useful as a lower
- // bound.
- // TODO(rossberg): Could use scope info to fix upper bounds for constant
- // bindings if we know that this code is never shared.
- for (size_t i = access.depth(); i > 0; --i) {
- if (context_type->IsContext()) {
- context_type = context_type->AsContext()->Outer();
- if (context_type->IsConstant()) {
- context = Handle<Context>::cast(context_type->AsConstant()->Value());
- }
- } else if (!context.is_null()) {
- context = handle(context.ToHandleChecked()->previous(), isolate());
- }
- }
- if (context.is_null()) {
- return Bounds::Unbounded(zone());
- } else {
- Handle<Object> value =
- handle(context.ToHandleChecked()->get(static_cast<int>(access.index())),
- isolate());
- Type* lower = TypeConstant(value);
- return Bounds(lower, Type::Any());
- }
+ // Since contexts are mutable, we just return the top.
+ return Type::Any();
}
-Bounds Typer::Visitor::TypeJSStoreContext(Node* node) {
+Type* Typer::Visitor::TypeJSStoreContext(Node* node) {
UNREACHABLE();
- return Bounds();
+ return nullptr;
}
-Bounds Typer::Visitor::TypeJSCreateFunctionContext(Node* node) {
- Bounds outer = ContextOperand(node);
- return Bounds(Type::Context(outer.upper, zone()));
+Type* Typer::Visitor::TypeJSLoadDynamic(Node* node) { return Type::Any(); }
+
+
+Type* Typer::Visitor::WrapContextTypeForInput(Node* node) {
+ Type* outer = TypeOrNone(NodeProperties::GetContextInput(node));
+ if (outer->Is(Type::None())) {
+ return Type::None();
+ } else {
+ DCHECK(outer->Maybe(Type::Internal()));
+ return Type::Context(outer, zone());
+ }
}
-Bounds Typer::Visitor::TypeJSCreateCatchContext(Node* node) {
- Bounds outer = ContextOperand(node);
- return Bounds(Type::Context(outer.upper, zone()));
+Type* Typer::Visitor::TypeJSCreateFunctionContext(Node* node) {
+ return WrapContextTypeForInput(node);
}
-Bounds Typer::Visitor::TypeJSCreateWithContext(Node* node) {
- Bounds outer = ContextOperand(node);
- return Bounds(Type::Context(outer.upper, zone()));
+Type* Typer::Visitor::TypeJSCreateCatchContext(Node* node) {
+ return WrapContextTypeForInput(node);
}
-Bounds Typer::Visitor::TypeJSCreateBlockContext(Node* node) {
- Bounds outer = ContextOperand(node);
- return Bounds(Type::Context(outer.upper, zone()));
+Type* Typer::Visitor::TypeJSCreateWithContext(Node* node) {
+ return WrapContextTypeForInput(node);
}
-Bounds Typer::Visitor::TypeJSCreateModuleContext(Node* node) {
+Type* Typer::Visitor::TypeJSCreateBlockContext(Node* node) {
+ return WrapContextTypeForInput(node);
+}
+
+
+Type* Typer::Visitor::TypeJSCreateModuleContext(Node* node) {
// TODO(rossberg): this is probably incorrect
- Bounds outer = ContextOperand(node);
- return Bounds(Type::Context(outer.upper, zone()));
+ return WrapContextTypeForInput(node);
}
-Bounds Typer::Visitor::TypeJSCreateScriptContext(Node* node) {
- Bounds outer = ContextOperand(node);
- return Bounds(Type::Context(outer.upper, zone()));
+Type* Typer::Visitor::TypeJSCreateScriptContext(Node* node) {
+ return WrapContextTypeForInput(node);
}
// JS other operators.
-Bounds Typer::Visitor::TypeJSYield(Node* node) {
- return Bounds::Unbounded(zone());
-}
+Type* Typer::Visitor::TypeJSYield(Node* node) { return Type::Any(); }
-Bounds Typer::Visitor::TypeJSCallConstruct(Node* node) {
- return Bounds(Type::None(), Type::Receiver());
+Type* Typer::Visitor::TypeJSCallConstruct(Node* node) {
+ return Type::Receiver();
}
Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) {
- return fun->IsFunction() ? fun->AsFunction()->Result() : Type::Any();
-}
-
-
-Bounds Typer::Visitor::TypeJSCallFunction(Node* node) {
- return TypeUnaryOp(node, JSCallFunctionTyper); // We ignore argument types.
-}
-
-
-Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
- return Bounds::Unbounded(zone());
-}
-
-
-Bounds Typer::Visitor::TypeJSDebugger(Node* node) {
- return Bounds::Unbounded(zone());
-}
-
-
-// Simplified operators.
-
-
-Bounds Typer::Visitor::TypeAnyToBoolean(Node* node) {
- return TypeUnaryOp(node, ToBoolean);
-}
-
-
-Bounds Typer::Visitor::TypeBooleanNot(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeBooleanToNumber(Node* node) {
- return Bounds(Type::None(zone()), typer_->zero_or_one);
-}
-
-
-Bounds Typer::Visitor::TypeNumberEqual(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeNumberLessThan(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeNumberLessThanOrEqual(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeNumberAdd(Node* node) {
- return Bounds(Type::None(zone()), Type::Number(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeNumberSubtract(Node* node) {
- return Bounds(Type::None(zone()), Type::Number(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeNumberMultiply(Node* node) {
- return Bounds(Type::None(zone()), Type::Number(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeNumberDivide(Node* node) {
- return Bounds(Type::None(zone()), Type::Number(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeNumberModulus(Node* node) {
- return Bounds(Type::None(zone()), Type::Number(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeNumberToInt32(Node* node) {
- return TypeUnaryOp(node, NumberToInt32);
-}
-
-
-Bounds Typer::Visitor::TypeNumberToUint32(Node* node) {
- return TypeUnaryOp(node, NumberToUint32);
-}
-
-
-Bounds Typer::Visitor::TypeReferenceEqual(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeStringEqual(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeStringLessThan(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeStringLessThanOrEqual(Node* node) {
- return Bounds(Type::None(zone()), Type::Boolean(zone()));
-}
-
-
-Bounds Typer::Visitor::TypeStringAdd(Node* node) {
- return Bounds(Type::None(zone()), Type::String(zone()));
-}
-
-
-static Type* ChangeRepresentation(Type* type, Type* rep, Zone* zone) {
- // TODO(neis): Enable when expressible.
- /*
- return Type::Union(
- Type::Intersect(type, Type::Semantic(), zone),
- Type::Intersect(rep, Type::Representation(), zone), zone);
- */
- return type;
-}
-
-
-Bounds Typer::Visitor::TypeChangeTaggedToInt32(Node* node) {
- Bounds arg = Operand(node, 0);
- // TODO(neis): DCHECK(arg.upper->Is(Type::Signed32()));
- return Bounds(
- ChangeRepresentation(arg.lower, Type::UntaggedSigned32(), zone()),
- ChangeRepresentation(arg.upper, Type::UntaggedSigned32(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeTaggedToUint32(Node* node) {
- Bounds arg = Operand(node, 0);
- // TODO(neis): DCHECK(arg.upper->Is(Type::Unsigned32()));
- return Bounds(
- ChangeRepresentation(arg.lower, Type::UntaggedUnsigned32(), zone()),
- ChangeRepresentation(arg.upper, Type::UntaggedUnsigned32(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) {
- Bounds arg = Operand(node, 0);
- // TODO(neis): DCHECK(arg.upper->Is(Type::Number()));
- return Bounds(
- ChangeRepresentation(arg.lower, Type::UntaggedFloat64(), zone()),
- ChangeRepresentation(arg.upper, Type::UntaggedFloat64(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeInt32ToTagged(Node* node) {
- Bounds arg = Operand(node, 0);
- // TODO(neis): DCHECK(arg.upper->Is(Type::Signed32()));
- return Bounds(
- ChangeRepresentation(arg.lower, Type::Tagged(), zone()),
- ChangeRepresentation(arg.upper, Type::Tagged(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeUint32ToTagged(Node* node) {
- Bounds arg = Operand(node, 0);
- // TODO(neis): DCHECK(arg.upper->Is(Type::Unsigned32()));
- return Bounds(
- ChangeRepresentation(arg.lower, Type::Tagged(), zone()),
- ChangeRepresentation(arg.upper, Type::Tagged(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeFloat64ToTagged(Node* node) {
- Bounds arg = Operand(node, 0);
- // TODO(neis): CHECK(arg.upper->Is(Type::Number()));
- return Bounds(
- ChangeRepresentation(arg.lower, Type::Tagged(), zone()),
- ChangeRepresentation(arg.upper, Type::Tagged(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeBoolToBit(Node* node) {
- Bounds arg = Operand(node, 0);
- // TODO(neis): DCHECK(arg.upper->Is(Type::Boolean()));
- return Bounds(
- ChangeRepresentation(arg.lower, Type::UntaggedBit(), zone()),
- ChangeRepresentation(arg.upper, Type::UntaggedBit(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeBitToBool(Node* node) {
- Bounds arg = Operand(node, 0);
- // TODO(neis): DCHECK(arg.upper->Is(Type::Boolean()));
- return Bounds(
- ChangeRepresentation(arg.lower, Type::TaggedPointer(), zone()),
- ChangeRepresentation(arg.upper, Type::TaggedPointer(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeLoadField(Node* node) {
- return Bounds(FieldAccessOf(node->op()).type);
-}
-
-
-Bounds Typer::Visitor::TypeLoadBuffer(Node* node) {
- // TODO(bmeurer): This typing is not yet correct. Since we can still access
- // out of bounds, the type in the general case has to include Undefined.
- switch (BufferAccessOf(node->op()).external_array_type()) {
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case kExternal##Type##Array: \
- return Bounds(typer_->cache_->Get(k##Type));
- TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
+ if (fun->IsFunction()) {
+ return fun->AsFunction()->Result();
}
- UNREACHABLE();
- return Bounds();
-}
-
-
-Bounds Typer::Visitor::TypeLoadElement(Node* node) {
- return Bounds(ElementAccessOf(node->op()).type);
-}
-
-
-Bounds Typer::Visitor::TypeStoreField(Node* node) {
- UNREACHABLE();
- return Bounds();
-}
-
-
-Bounds Typer::Visitor::TypeStoreBuffer(Node* node) {
- UNREACHABLE();
- return Bounds();
-}
-
-
-Bounds Typer::Visitor::TypeStoreElement(Node* node) {
- UNREACHABLE();
- return Bounds();
-}
-
-
-Bounds Typer::Visitor::TypeObjectIsSmi(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeObjectIsNonNegativeSmi(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-// Machine operators.
-
-Bounds Typer::Visitor::TypeLoad(Node* node) {
- return Bounds::Unbounded(zone());
-}
-
-
-Bounds Typer::Visitor::TypeStore(Node* node) {
- UNREACHABLE();
- return Bounds();
-}
-
-
-Bounds Typer::Visitor::TypeWord32And(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeWord32Or(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeWord32Xor(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeWord32Shl(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeWord32Shr(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeWord32Sar(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeWord32Ror(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeWord32Equal(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeWord64And(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeWord64Or(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeWord64Xor(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeWord64Shl(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeWord64Shr(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeWord64Sar(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeWord64Ror(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeWord64Equal(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeInt32Add(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeInt32AddWithOverflow(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeInt32Sub(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeInt32SubWithOverflow(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeInt32Mul(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeInt32MulHigh(Node* node) {
- return Bounds(Type::Signed32());
-}
-
-
-Bounds Typer::Visitor::TypeInt32Div(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeInt32Mod(Node* node) {
- return Bounds(Type::Integral32());
-}
-
-
-Bounds Typer::Visitor::TypeInt32LessThan(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeInt32LessThanOrEqual(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeUint32Div(Node* node) {
- return Bounds(Type::Unsigned32());
-}
-
-
-Bounds Typer::Visitor::TypeUint32LessThan(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeUint32LessThanOrEqual(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeUint32Mod(Node* node) {
- return Bounds(Type::Unsigned32());
-}
-
-
-Bounds Typer::Visitor::TypeUint32MulHigh(Node* node) {
- return Bounds(Type::Unsigned32());
-}
-
-
-Bounds Typer::Visitor::TypeInt64Add(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeInt64Sub(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeInt64Mul(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeInt64Div(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeInt64Mod(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeInt64LessThan(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeInt64LessThanOrEqual(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeUint64Div(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeUint64LessThan(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeUint64Mod(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeChangeFloat32ToFloat64(Node* node) {
- return Bounds(Type::Intersect(
- Type::Number(), Type::UntaggedFloat64(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeFloat64ToInt32(Node* node) {
- return Bounds(Type::Intersect(
- Type::Signed32(), Type::UntaggedSigned32(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeFloat64ToUint32(Node* node) {
- return Bounds(Type::Intersect(
- Type::Unsigned32(), Type::UntaggedUnsigned32(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeInt32ToFloat64(Node* node) {
- return Bounds(Type::Intersect(
- Type::Signed32(), Type::UntaggedFloat64(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeInt32ToInt64(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeChangeUint32ToFloat64(Node* node) {
- return Bounds(Type::Intersect(
- Type::Unsigned32(), Type::UntaggedFloat64(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeChangeUint32ToUint64(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeTruncateFloat64ToFloat32(Node* node) {
- return Bounds(Type::Intersect(
- Type::Number(), Type::UntaggedFloat32(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeTruncateFloat64ToInt32(Node* node) {
- return Bounds(Type::Intersect(
- Type::Signed32(), Type::UntaggedSigned32(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeTruncateInt64ToInt32(Node* node) {
- return Bounds(Type::Intersect(
- Type::Signed32(), Type::UntaggedSigned32(), zone()));
-}
-
-
-Bounds Typer::Visitor::TypeFloat64Add(Node* node) {
- return Bounds(Type::Number());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64Sub(Node* node) {
- return Bounds(Type::Number());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64Mul(Node* node) {
- return Bounds(Type::Number());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64Div(Node* node) {
- return Bounds(Type::Number());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64Mod(Node* node) {
- return Bounds(Type::Number());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64Sqrt(Node* node) {
- return Bounds(Type::Number());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64Equal(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64LessThan(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64LessThanOrEqual(Node* node) {
- return Bounds(Type::Boolean());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64Floor(Node* node) {
- // TODO(sigurds): We could have a tighter bound here.
- return Bounds(Type::Number());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64Ceil(Node* node) {
- // TODO(sigurds): We could have a tighter bound here.
- return Bounds(Type::Number());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64RoundTruncate(Node* node) {
- // TODO(sigurds): We could have a tighter bound here.
- return Bounds(Type::Number());
-}
-
-
-Bounds Typer::Visitor::TypeFloat64RoundTiesAway(Node* node) {
- // TODO(sigurds): We could have a tighter bound here.
- return Bounds(Type::Number());
-}
-
-
-Bounds Typer::Visitor::TypeLoadStackPointer(Node* node) {
- return Bounds(Type::Internal());
-}
-
-
-Bounds Typer::Visitor::TypeCheckedLoad(Node* node) {
- return Bounds::Unbounded(zone());
-}
-
-
-Bounds Typer::Visitor::TypeCheckedStore(Node* node) {
- UNREACHABLE();
- return Bounds();
-}
-
-
-// Heap constants.
-
-
-Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
- if (value->IsJSFunction()) {
- if (JSFunction::cast(*value)->shared()->HasBuiltinFunctionId()) {
- switch (JSFunction::cast(*value)->shared()->builtin_function_id()) {
+ if (fun->IsConstant() && fun->AsConstant()->Value()->IsJSFunction()) {
+ Handle<JSFunction> function =
+ Handle<JSFunction>::cast(fun->AsConstant()->Value());
+ if (function->shared()->HasBuiltinFunctionId()) {
+ switch (function->shared()->builtin_function_id()) {
case kMathRandom:
- return typer_->random_fun_;
+ return Type::OrderedNumber();
case kMathFloor:
- return typer_->weakint_fun1_;
case kMathRound:
- return typer_->weakint_fun1_;
case kMathCeil:
- return typer_->weakint_fun1_;
+ return t->cache_.kIntegerOrMinusZeroOrNaN;
// Unary math functions.
- case kMathAbs: // TODO(rossberg): can't express overloading
+ case kMathAbs:
case kMathLog:
case kMathExp:
case kMathSqrt:
@@ -2055,52 +1513,925 @@
case kMathAsin:
case kMathAtan:
case kMathFround:
- return typer_->cache_->Get(kNumberFunc1);
+ return Type::Number();
// Binary math functions.
case kMathAtan2:
case kMathPow:
case kMathMax:
case kMathMin:
- return typer_->cache_->Get(kNumberFunc2);
+ return Type::Number();
case kMathImul:
- return typer_->cache_->Get(kImulFunc);
+ return Type::Signed32();
case kMathClz32:
- return typer_->cache_->Get(kClz32Func);
+ return t->cache_.kZeroToThirtyTwo;
+ // String functions.
+ case kStringCharAt:
+ case kStringFromCharCode:
+ return Type::String();
+ // Array functions.
+ case kArrayIndexOf:
+ case kArrayLastIndexOf:
+ return Type::Number();
default:
break;
}
- } else if (JSFunction::cast(*value)->IsBuiltin() && !context().is_null()) {
- Handle<Context> native =
- handle(context().ToHandleChecked()->native_context(), isolate());
- if (*value == native->array_buffer_fun()) {
- return typer_->cache_->Get(kArrayBufferFunc);
- } else if (*value == native->int8_array_fun()) {
- return typer_->cache_->Get(kInt8ArrayFunc);
- } else if (*value == native->int16_array_fun()) {
- return typer_->cache_->Get(kInt16ArrayFunc);
- } else if (*value == native->int32_array_fun()) {
- return typer_->cache_->Get(kInt32ArrayFunc);
- } else if (*value == native->uint8_array_fun()) {
- return typer_->cache_->Get(kUint8ArrayFunc);
- } else if (*value == native->uint16_array_fun()) {
- return typer_->cache_->Get(kUint16ArrayFunc);
- } else if (*value == native->uint32_array_fun()) {
- return typer_->cache_->Get(kUint32ArrayFunc);
- } else if (*value == native->float32_array_fun()) {
- return typer_->cache_->Get(kFloat32ArrayFunc);
- } else if (*value == native->float64_array_fun()) {
- return typer_->cache_->Get(kFloat64ArrayFunc);
- }
}
- } else if (value->IsJSTypedArray()) {
+ }
+ return Type::Any();
+}
+
+
+Type* Typer::Visitor::TypeJSCallFunction(Node* node) {
+ // TODO(bmeurer): We could infer better types if we wouldn't ignore the
+ // argument types for the JSCallFunctionTyper above.
+ return TypeUnaryOp(node, JSCallFunctionTyper);
+}
+
+
+Type* Typer::Visitor::TypeJSCallRuntime(Node* node) {
+ switch (CallRuntimeParametersOf(node->op()).id()) {
+ case Runtime::kInlineIsSmi:
+ case Runtime::kInlineIsArray:
+ case Runtime::kInlineIsDate:
+ case Runtime::kInlineIsTypedArray:
+ case Runtime::kInlineIsMinusZero:
+ case Runtime::kInlineIsFunction:
+ case Runtime::kInlineIsRegExp:
+ case Runtime::kInlineIsJSReceiver:
+ return Type::Boolean(zone());
+ case Runtime::kInlineDoubleLo:
+ case Runtime::kInlineDoubleHi:
+ return Type::Signed32();
+ case Runtime::kInlineConstructDouble:
+ case Runtime::kInlineMathFloor:
+ case Runtime::kInlineMathSqrt:
+ case Runtime::kInlineMathAcos:
+ case Runtime::kInlineMathAsin:
+ case Runtime::kInlineMathAtan:
+ case Runtime::kInlineMathAtan2:
+ return Type::Number();
+ case Runtime::kInlineMathClz32:
+ return Type::Range(0, 32, zone());
+ case Runtime::kInlineCreateIterResultObject:
+ case Runtime::kInlineRegExpConstructResult:
+ return Type::OtherObject();
+ case Runtime::kInlineSubString:
+ return Type::String();
+ case Runtime::kInlineToInteger:
+ return TypeUnaryOp(node, ToInteger);
+ case Runtime::kInlineToLength:
+ return TypeUnaryOp(node, ToLength);
+ case Runtime::kInlineToName:
+ return TypeUnaryOp(node, ToName);
+ case Runtime::kInlineToNumber:
+ return TypeUnaryOp(node, ToNumber);
+ case Runtime::kInlineToObject:
+ return TypeUnaryOp(node, ToObject);
+ case Runtime::kInlineToPrimitive:
+ case Runtime::kInlineToPrimitive_Number:
+ case Runtime::kInlineToPrimitive_String:
+ return TypeUnaryOp(node, ToPrimitive);
+ case Runtime::kInlineToString:
+ return TypeUnaryOp(node, ToString);
+ case Runtime::kHasInPrototypeChain:
+ return Type::Boolean();
+ default:
+ break;
+ }
+ return Type::Any();
+}
+
+
+Type* Typer::Visitor::TypeJSConvertReceiver(Node* node) {
+ return Type::Receiver();
+}
+
+
+Type* Typer::Visitor::TypeJSForInNext(Node* node) {
+ return Type::Union(Type::Name(), Type::Undefined(), zone());
+}
+
+
+Type* Typer::Visitor::TypeJSForInPrepare(Node* node) {
+ // TODO(bmeurer): Return a tuple type here.
+ return Type::Any();
+}
+
+
+Type* Typer::Visitor::TypeJSForInDone(Node* node) {
+ return Type::Boolean(zone());
+}
+
+
+Type* Typer::Visitor::TypeJSForInStep(Node* node) {
+ STATIC_ASSERT(Map::EnumLengthBits::kMax <= FixedArray::kMaxLength);
+ return Type::Range(1, FixedArray::kMaxLength + 1, zone());
+}
+
+
+Type* Typer::Visitor::TypeJSLoadMessage(Node* node) { return Type::Any(); }
+
+
+Type* Typer::Visitor::TypeJSStoreMessage(Node* node) {
+ UNREACHABLE();
+ return nullptr;
+}
+
+
+Type* Typer::Visitor::TypeJSStackCheck(Node* node) { return Type::Any(); }
+
+
+// Simplified operators.
+
+
+Type* Typer::Visitor::TypeBooleanNot(Node* node) {
+ return Type::Boolean(zone());
+}
+
+
+Type* Typer::Visitor::TypeBooleanToNumber(Node* node) {
+ return TypeUnaryOp(node, ToNumber);
+}
+
+
+Type* Typer::Visitor::TypeNumberEqual(Node* node) {
+ return Type::Boolean(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberLessThan(Node* node) {
+ return Type::Boolean(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberLessThanOrEqual(Node* node) {
+ return Type::Boolean(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberAdd(Node* node) { return Type::Number(zone()); }
+
+
+Type* Typer::Visitor::TypeNumberSubtract(Node* node) {
+ return Type::Number(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberMultiply(Node* node) {
+ return Type::Number(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberDivide(Node* node) {
+ return Type::Number(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberModulus(Node* node) {
+ return Type::Number(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberBitwiseOr(Node* node) {
+ return Type::Signed32(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberBitwiseXor(Node* node) {
+ return Type::Signed32(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberBitwiseAnd(Node* node) {
+ return Type::Signed32(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberShiftLeft(Node* node) {
+ return Type::Signed32(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberShiftRight(Node* node) {
+ return Type::Signed32(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberShiftRightLogical(Node* node) {
+ return Type::Unsigned32(zone());
+}
+
+
+Type* Typer::Visitor::TypeNumberToInt32(Node* node) {
+ return TypeUnaryOp(node, NumberToInt32);
+}
+
+
+Type* Typer::Visitor::TypeNumberToUint32(Node* node) {
+ return TypeUnaryOp(node, NumberToUint32);
+}
+
+
+Type* Typer::Visitor::TypeNumberIsHoleNaN(Node* node) {
+ return Type::Boolean(zone());
+}
+
+
+Type* Typer::Visitor::TypePlainPrimitiveToNumber(Node* node) {
+ return TypeUnaryOp(node, ToNumber);
+}
+
+
+// static
+Type* Typer::Visitor::ReferenceEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+ if (lhs->IsConstant() && rhs->Is(lhs)) {
+ return t->singleton_true_;
+ }
+ return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::TypeReferenceEqual(Node* node) {
+ return TypeBinaryOp(node, ReferenceEqualTyper);
+}
+
+
+Type* Typer::Visitor::TypeStringEqual(Node* node) {
+ return Type::Boolean(zone());
+}
+
+
+Type* Typer::Visitor::TypeStringLessThan(Node* node) {
+ return Type::Boolean(zone());
+}
+
+
+Type* Typer::Visitor::TypeStringLessThanOrEqual(Node* node) {
+ return Type::Boolean(zone());
+}
+
+
+namespace {
+
+Type* ChangeRepresentation(Type* type, Type* rep, Zone* zone) {
+ return Type::Union(Type::Semantic(type, zone),
+ Type::Representation(rep, zone), zone);
+}
+
+} // namespace
+
+
+Type* Typer::Visitor::TypeChangeTaggedToInt32(Node* node) {
+ Type* arg = Operand(node, 0);
+ // TODO(neis): DCHECK(arg->Is(Type::Signed32()));
+ return ChangeRepresentation(arg, Type::UntaggedIntegral32(), zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeTaggedToUint32(Node* node) {
+ Type* arg = Operand(node, 0);
+ // TODO(neis): DCHECK(arg->Is(Type::Unsigned32()));
+ return ChangeRepresentation(arg, Type::UntaggedIntegral32(), zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) {
+ Type* arg = Operand(node, 0);
+ // TODO(neis): DCHECK(arg->Is(Type::Number()));
+ return ChangeRepresentation(arg, Type::UntaggedFloat64(), zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeInt32ToTagged(Node* node) {
+ Type* arg = Operand(node, 0);
+ // TODO(neis): DCHECK(arg->Is(Type::Signed32()));
+ Type* rep =
+ arg->Is(Type::SignedSmall()) ? Type::TaggedSigned() : Type::Tagged();
+ return ChangeRepresentation(arg, rep, zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeUint32ToTagged(Node* node) {
+ Type* arg = Operand(node, 0);
+ // TODO(neis): DCHECK(arg->Is(Type::Unsigned32()));
+ return ChangeRepresentation(arg, Type::Tagged(), zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeFloat64ToTagged(Node* node) {
+ Type* arg = Operand(node, 0);
+ // TODO(neis): CHECK(arg.upper->Is(Type::Number()));
+ return ChangeRepresentation(arg, Type::Tagged(), zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeBoolToBit(Node* node) {
+ Type* arg = Operand(node, 0);
+ // TODO(neis): DCHECK(arg.upper->Is(Type::Boolean()));
+ return ChangeRepresentation(arg, Type::UntaggedBit(), zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeBitToBool(Node* node) {
+ Type* arg = Operand(node, 0);
+ // TODO(neis): DCHECK(arg.upper->Is(Type::Boolean()));
+ return ChangeRepresentation(arg, Type::TaggedPointer(), zone());
+}
+
+
+Type* Typer::Visitor::TypeAllocate(Node* node) { return Type::TaggedPointer(); }
+
+
+namespace {
+
+MaybeHandle<Map> GetStableMapFromObjectType(Type* object_type) {
+ if (object_type->IsConstant() &&
+ object_type->AsConstant()->Value()->IsHeapObject()) {
+ Handle<Map> object_map(
+ Handle<HeapObject>::cast(object_type->AsConstant()->Value())->map());
+ if (object_map->is_stable()) return object_map;
+ } else if (object_type->IsClass()) {
+ Handle<Map> object_map = object_type->AsClass()->Map();
+ if (object_map->is_stable()) return object_map;
+ }
+ return MaybeHandle<Map>();
+}
+
+} // namespace
+
+
+Type* Typer::Visitor::TypeLoadField(Node* node) {
+ FieldAccess const& access = FieldAccessOf(node->op());
+ if (access.base_is_tagged == kTaggedBase &&
+ access.offset == HeapObject::kMapOffset) {
+ // The type of LoadField[Map](o) is Constant(map) if map is stable and
+ // either
+ // (a) o has type Constant(object) and map == object->map, or
+ // (b) o has type Class(map),
+ // and either
+ // (1) map cannot transition further, or
+ // (2) deoptimization is enabled and we can add a code dependency on the
+ // stability of map (to guard the Constant type information).
+ Type* const object = Operand(node, 0);
+ if (object->Is(Type::None())) return Type::None();
+ Handle<Map> object_map;
+ if (GetStableMapFromObjectType(object).ToHandle(&object_map)) {
+ if (object_map->CanTransition()) {
+ if (flags() & kDeoptimizationEnabled) {
+ dependencies()->AssumeMapStable(object_map);
+ } else {
+ return access.type;
+ }
+ }
+ Type* object_map_type = Type::Constant(object_map, zone());
+ DCHECK(object_map_type->Is(access.type));
+ return object_map_type;
+ }
+ }
+ return access.type;
+}
+
+
+Type* Typer::Visitor::TypeLoadBuffer(Node* node) {
+ // TODO(bmeurer): This typing is not yet correct. Since we can still access
+ // out of bounds, the type in the general case has to include Undefined.
+ switch (BufferAccessOf(node->op()).external_array_type()) {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return typer_->cache_.k##Type;
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+ }
+ UNREACHABLE();
+ return nullptr;
+}
+
+
+Type* Typer::Visitor::TypeLoadElement(Node* node) {
+ return ElementAccessOf(node->op()).type;
+}
+
+
+Type* Typer::Visitor::TypeStoreField(Node* node) {
+ UNREACHABLE();
+ return nullptr;
+}
+
+
+Type* Typer::Visitor::TypeStoreBuffer(Node* node) {
+ UNREACHABLE();
+ return nullptr;
+}
+
+
+Type* Typer::Visitor::TypeStoreElement(Node* node) {
+ UNREACHABLE();
+ return nullptr;
+}
+
+
+Type* Typer::Visitor::TypeObjectIsNumber(Node* node) {
+ Type* arg = Operand(node, 0);
+ if (arg->Is(Type::None())) return Type::None();
+ if (arg->Is(Type::Number())) return typer_->singleton_true_;
+ if (!arg->Maybe(Type::Number())) return typer_->singleton_false_;
+ return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::TypeObjectIsSmi(Node* node) {
+ Type* arg = Operand(node, 0);
+ if (arg->Is(Type::None())) return Type::None();
+ if (arg->Is(Type::TaggedSigned())) return typer_->singleton_true_;
+ if (arg->Is(Type::TaggedPointer())) return typer_->singleton_false_;
+ return Type::Boolean();
+}
+
+
+// Machine operators.
+
+Type* Typer::Visitor::TypeLoad(Node* node) { return Type::Any(); }
+
+
+Type* Typer::Visitor::TypeStore(Node* node) {
+ UNREACHABLE();
+ return nullptr;
+}
+
+
+Type* Typer::Visitor::TypeWord32And(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeWord32Or(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeWord32Xor(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeWord32Shl(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeWord32Shr(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeWord32Sar(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeWord32Ror(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeWord32Equal(Node* node) { return Type::Boolean(); }
+
+
+Type* Typer::Visitor::TypeWord32Clz(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeWord32Ctz(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeWord32Popcnt(Node* node) {
+ return Type::Integral32();
+}
+
+
+Type* Typer::Visitor::TypeWord64And(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeWord64Or(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeWord64Xor(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeWord64Shl(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeWord64Shr(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeWord64Sar(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeWord64Ror(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeWord64Clz(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeWord64Ctz(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeWord64Popcnt(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeWord64Equal(Node* node) { return Type::Boolean(); }
+
+
+Type* Typer::Visitor::TypeInt32Add(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeInt32AddWithOverflow(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeInt32Sub(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeInt32SubWithOverflow(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeInt32Mul(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeInt32MulHigh(Node* node) { return Type::Signed32(); }
+
+
+Type* Typer::Visitor::TypeInt32Div(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeInt32Mod(Node* node) { return Type::Integral32(); }
+
+
+Type* Typer::Visitor::TypeInt32LessThan(Node* node) { return Type::Boolean(); }
+
+
+Type* Typer::Visitor::TypeInt32LessThanOrEqual(Node* node) {
+ return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::TypeUint32Div(Node* node) { return Type::Unsigned32(); }
+
+
+Type* Typer::Visitor::TypeUint32LessThan(Node* node) { return Type::Boolean(); }
+
+
+Type* Typer::Visitor::TypeUint32LessThanOrEqual(Node* node) {
+ return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::TypeUint32Mod(Node* node) { return Type::Unsigned32(); }
+
+
+Type* Typer::Visitor::TypeUint32MulHigh(Node* node) {
+ return Type::Unsigned32();
+}
+
+
+Type* Typer::Visitor::TypeInt64Add(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeInt64AddWithOverflow(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeInt64Sub(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeInt64SubWithOverflow(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeInt64Mul(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeInt64Div(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeInt64Mod(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeInt64LessThan(Node* node) { return Type::Boolean(); }
+
+
+Type* Typer::Visitor::TypeInt64LessThanOrEqual(Node* node) {
+ return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::TypeUint64Div(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeUint64LessThan(Node* node) { return Type::Boolean(); }
+
+
+Type* Typer::Visitor::TypeUint64LessThanOrEqual(Node* node) {
+ return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::TypeUint64Mod(Node* node) { return Type::Internal(); }
+
+
+Type* Typer::Visitor::TypeChangeFloat32ToFloat64(Node* node) {
+ return Type::Intersect(Type::Number(), Type::UntaggedFloat64(), zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeFloat64ToInt32(Node* node) {
+ return Type::Intersect(Type::Signed32(), Type::UntaggedIntegral32(), zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeFloat64ToUint32(Node* node) {
+ return Type::Intersect(Type::Unsigned32(), Type::UntaggedIntegral32(),
+ zone());
+}
+
+
+Type* Typer::Visitor::TypeTryTruncateFloat32ToInt64(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeTryTruncateFloat64ToInt64(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeTryTruncateFloat32ToUint64(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeTryTruncateFloat64ToUint64(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeChangeInt32ToFloat64(Node* node) {
+ return Type::Intersect(Type::Signed32(), Type::UntaggedFloat64(), zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeInt32ToInt64(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeChangeUint32ToFloat64(Node* node) {
+ return Type::Intersect(Type::Unsigned32(), Type::UntaggedFloat64(), zone());
+}
+
+
+Type* Typer::Visitor::TypeChangeUint32ToUint64(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeTruncateFloat64ToFloat32(Node* node) {
+ return Type::Intersect(Type::Number(), Type::UntaggedFloat32(), zone());
+}
+
+
+Type* Typer::Visitor::TypeTruncateFloat64ToInt32(Node* node) {
+ return Type::Intersect(Type::Signed32(), Type::UntaggedIntegral32(), zone());
+}
+
+
+Type* Typer::Visitor::TypeTruncateInt64ToInt32(Node* node) {
+ return Type::Intersect(Type::Signed32(), Type::UntaggedIntegral32(), zone());
+}
+
+
+Type* Typer::Visitor::TypeRoundInt64ToFloat32(Node* node) {
+ return Type::Intersect(Type::PlainNumber(), Type::UntaggedFloat32(), zone());
+}
+
+
+Type* Typer::Visitor::TypeRoundInt64ToFloat64(Node* node) {
+ return Type::Intersect(Type::PlainNumber(), Type::UntaggedFloat64(), zone());
+}
+
+
+Type* Typer::Visitor::TypeRoundUint64ToFloat32(Node* node) {
+ return Type::Intersect(Type::PlainNumber(), Type::UntaggedFloat32(), zone());
+}
+
+
+Type* Typer::Visitor::TypeRoundUint64ToFloat64(Node* node) {
+ return Type::Intersect(Type::PlainNumber(), Type::UntaggedFloat64(), zone());
+}
+
+
+Type* Typer::Visitor::TypeBitcastFloat32ToInt32(Node* node) {
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeBitcastFloat64ToInt64(Node* node) {
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeBitcastInt32ToFloat32(Node* node) {
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeBitcastInt64ToFloat64(Node* node) {
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat32Add(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat32Sub(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat32Mul(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat32Div(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat32Max(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat32Min(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat32Abs(Node* node) {
+ // TODO(turbofan): We should be able to infer a better type here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat32Sqrt(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat32Equal(Node* node) { return Type::Boolean(); }
+
+
+Type* Typer::Visitor::TypeFloat32LessThan(Node* node) {
+ return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::TypeFloat32LessThanOrEqual(Node* node) {
+ return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::TypeFloat64Add(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat64Sub(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat64Mul(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat64Div(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat64Mod(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat64Max(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat64Min(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat64Abs(Node* node) {
+ // TODO(turbofan): We should be able to infer a better type here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat64Sqrt(Node* node) { return Type::Number(); }
+
+
+Type* Typer::Visitor::TypeFloat64Equal(Node* node) { return Type::Boolean(); }
+
+
+Type* Typer::Visitor::TypeFloat64LessThan(Node* node) {
+ return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::TypeFloat64LessThanOrEqual(Node* node) {
+ return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::TypeFloat32RoundDown(Node* node) {
+ // TODO(sigurds): We could have a tighter bound here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat64RoundDown(Node* node) {
+ // TODO(sigurds): We could have a tighter bound here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat32RoundUp(Node* node) {
+ // TODO(sigurds): We could have a tighter bound here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat64RoundUp(Node* node) {
+ // TODO(sigurds): We could have a tighter bound here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat32RoundTruncate(Node* node) {
+ // TODO(sigurds): We could have a tighter bound here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat64RoundTruncate(Node* node) {
+ // TODO(sigurds): We could have a tighter bound here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat64RoundTiesAway(Node* node) {
+ // TODO(sigurds): We could have a tighter bound here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat32RoundTiesEven(Node* node) {
+ // TODO(sigurds): We could have a tighter bound here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat64RoundTiesEven(Node* node) {
+ // TODO(sigurds): We could have a tighter bound here.
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat64ExtractLowWord32(Node* node) {
+ return Type::Signed32();
+}
+
+
+Type* Typer::Visitor::TypeFloat64ExtractHighWord32(Node* node) {
+ return Type::Signed32();
+}
+
+
+Type* Typer::Visitor::TypeFloat64InsertLowWord32(Node* node) {
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeFloat64InsertHighWord32(Node* node) {
+ return Type::Number();
+}
+
+
+Type* Typer::Visitor::TypeLoadStackPointer(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeLoadFramePointer(Node* node) {
+ return Type::Internal();
+}
+
+
+Type* Typer::Visitor::TypeCheckedLoad(Node* node) { return Type::Any(); }
+
+
+Type* Typer::Visitor::TypeCheckedStore(Node* node) {
+ UNREACHABLE();
+ return nullptr;
+}
+
+
+// Heap constants.
+
+
+Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
+ if (value->IsJSTypedArray()) {
switch (JSTypedArray::cast(*value)->type()) {
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case kExternal##Type##Array: \
- return typer_->cache_->Get(k##Type##Array);
+ return typer_->cache_.k##Type##Array;
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
}
}
+ if (Type::IsInteger(*value)) {
+ return Type::Range(value->Number(), value->Number(), zone());
+ }
return Type::Constant(value, zone());
}