Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Unified Diff: src/compiler/typer.cc

Issue 509343002: Better typing and type verification (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Drop typedness from graph Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/compiler/typer.cc
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index 73fe41d58291ff3dfbe0637b6dcc7c103b0041e9..f532355f4589315ca2cd0cb4f4ecefdbb6be8a22 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -14,7 +14,20 @@ namespace v8 {
namespace internal {
namespace compiler {
-Typer::Typer(Zone* zone) : zone_(zone) {
+
+class Typer::Decorator : public GraphDecorator {
+ public:
+ explicit Decorator(Typer* typer) : typer_(typer) {}
+ virtual void Decorate(Node* node);
+
+ private:
+ Typer* typer_;
+};
+
+
+Typer::Typer(Graph* graph, MaybeHandle<Context> context)
+ : graph_(graph), context_(context), decorator_(NULL) {
+ Zone* zone = this->zone();
Type* number = Type::Number(zone);
Type* signed32 = Type::Signed32(zone);
Type* unsigned32 = Type::Unsigned32(zone);
@@ -62,39 +75,47 @@ Typer::Typer(Zone* zone) : zone_(zone) {
}
+Typer::~Typer() {
+ if (decorator_) graph_->RemoveDecorator(decorator_);
+}
+
+
class Typer::Visitor : public NullNodeVisitor {
public:
- Visitor(Typer* typer, MaybeHandle<Context> context)
- : typer_(typer), context_(context) {}
+ explicit Visitor(Typer* typer) : typer_(typer) {}
Bounds TypeNode(Node* node) {
switch (node->opcode()) {
#define DECLARE_CASE(x) case IrOpcode::k##x: return Type##x(node);
+ DECLARE_CASE(Start)
VALUE_OP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(x) case IrOpcode::k##x:
- CONTROL_OP_LIST(DECLARE_CASE)
+ DECLARE_CASE(End)
+ INNER_CONTROL_OP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
break;
}
- return Bounds(Type::None(zone()));
+ UNREACHABLE();
+ return Bounds();
}
Type* TypeConstant(Handle<Object> value);
protected:
#define DECLARE_METHOD(x) inline Bounds Type##x(Node* node);
+ DECLARE_METHOD(Start)
VALUE_OP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
- Bounds OperandType(Node* node, int i) {
- return NodeProperties::GetBounds(NodeProperties::GetValueInput(node, i));
+ Bounds operand(Node* node, int i) {
+ Node* operand_node = NodeProperties::GetValueInput(node, i);
+ return GetBoundsOrNone(operand_node);
}
- Type* ContextType(Node* node) {
- Bounds result =
- NodeProperties::GetBounds(NodeProperties::GetContextInput(node));
+ Type* context_type(Node* node) {
+ Bounds result = GetBoundsOrNone(NodeProperties::GetContextInput(node));
DCHECK(result.upper->Is(Type::Internal()));
DCHECK(result.lower->Equals(result.upper));
return result.upper;
@@ -102,35 +123,31 @@ class Typer::Visitor : public NullNodeVisitor {
Zone* zone() { return typer_->zone(); }
Isolate* isolate() { return typer_->isolate(); }
- MaybeHandle<Context> context() { return context_; }
+ Graph* graph() { return typer_->graph(); }
+ MaybeHandle<Context> context() { return typer_->context(); }
private:
Typer* typer_;
- MaybeHandle<Context> context_;
+
+ Bounds GetBoundsOrNone(Node* node) {
+ return NodeProperties::IsTyped(node)
+ ? NodeProperties::GetBounds(node) : Bounds(Type::None(zone()));
+ }
};
class Typer::RunVisitor : public Typer::Visitor {
public:
- RunVisitor(Typer* typer, MaybeHandle<Context> context)
- : Visitor(typer, context),
+ explicit RunVisitor(Typer* typer)
+ : Visitor(typer),
phis(NodeSet::key_compare(), NodeSet::allocator_type(typer->zone())) {}
- GenericGraphVisit::Control Pre(Node* node) {
- return NodeProperties::IsControl(node)
- && node->opcode() != IrOpcode::kEnd
- && node->opcode() != IrOpcode::kMerge
- && node->opcode() != IrOpcode::kReturn
- ? GenericGraphVisit::SKIP : GenericGraphVisit::CONTINUE;
- }
-
GenericGraphVisit::Control Post(Node* node) {
- Bounds bounds = TypeNode(node);
- if (node->opcode() == IrOpcode::kPhi) {
- // Remember phis for least fixpoint iteration.
- phis.insert(node);
- } else {
+ if (OperatorProperties::HasValueOutput(node->op())) {
+ Bounds bounds = TypeNode(node);
NodeProperties::SetBounds(node, bounds);
+ // Remember phis for least fixpoint iteration.
+ if (node->opcode() == IrOpcode::kPhi) phis.insert(node);
}
return GenericGraphVisit::CONTINUE;
}
@@ -141,17 +158,20 @@ class Typer::RunVisitor : public Typer::Visitor {
class Typer::NarrowVisitor : public Typer::Visitor {
public:
- NarrowVisitor(Typer* typer, MaybeHandle<Context> context)
- : Visitor(typer, context) {}
+ explicit NarrowVisitor(Typer* typer) : Visitor(typer) {}
GenericGraphVisit::Control Pre(Node* node) {
- Bounds previous = NodeProperties::GetBounds(node);
- Bounds bounds = TypeNode(node);
- NodeProperties::SetBounds(node, Bounds::Both(bounds, previous, zone()));
- DCHECK(bounds.Narrows(previous));
- // Stop when nothing changed (but allow reentry in case it does later).
- return previous.Narrows(bounds)
- ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
+ if (OperatorProperties::HasValueOutput(node->op())) {
+ Bounds previous = NodeProperties::GetBounds(node);
+ Bounds bounds = TypeNode(node);
+ NodeProperties::SetBounds(node, Bounds::Both(bounds, previous, zone()));
+ DCHECK(bounds.Narrows(previous));
+ // Stop when nothing changed (but allow re-entry in case it does later).
+ return previous.Narrows(bounds)
+ ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
+ } else {
+ return GenericGraphVisit::SKIP;
+ }
}
GenericGraphVisit::Control Post(Node* node) {
@@ -162,18 +182,21 @@ class Typer::NarrowVisitor : public Typer::Visitor {
class Typer::WidenVisitor : public Typer::Visitor {
public:
- WidenVisitor(Typer* typer, MaybeHandle<Context> context)
- : Visitor(typer, context) {}
+ explicit WidenVisitor(Typer* typer) : Visitor(typer) {}
GenericGraphVisit::Control Pre(Node* node) {
- Bounds previous = NodeProperties::GetBounds(node);
- Bounds bounds = TypeNode(node);
- DCHECK(previous.lower->Is(bounds.lower));
- DCHECK(previous.upper->Is(bounds.upper));
- NodeProperties::SetBounds(node, bounds); // TODO(rossberg): Either?
- // Stop when nothing changed (but allow reentry in case it does later).
- return bounds.Narrows(previous)
- ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
+ if (OperatorProperties::HasValueOutput(node->op())) {
+ Bounds previous = NodeProperties::GetBounds(node);
+ Bounds bounds = TypeNode(node);
+ DCHECK(previous.lower->Is(bounds.lower));
+ DCHECK(previous.upper->Is(bounds.upper));
+ NodeProperties::SetBounds(node, bounds); // TODO(rossberg): Either?
+ // Stop when nothing changed (but allow re-entry in case it does later).
+ return bounds.Narrows(previous)
+ ? GenericGraphVisit::DEFER : GenericGraphVisit::REENTER;
+ } else {
+ return GenericGraphVisit::SKIP;
+ }
}
GenericGraphVisit::Control Post(Node* node) {
@@ -182,36 +205,47 @@ class Typer::WidenVisitor : public Typer::Visitor {
};
-void Typer::Run(Graph* graph, MaybeHandle<Context> context) {
- RunVisitor typing(this, context);
- graph->VisitNodeInputsFromEnd(&typing);
+void Typer::Run() {
+ RunVisitor typing(this);
+ graph_->VisitNodeInputsFromEnd(&typing);
// Find least fixpoint.
- for (NodeSetIter i = typing.phis.begin(); i != typing.phis.end(); ++i) {
- Widen(graph, *i, context);
+ WidenVisitor widen(this);
+ for (NodeSetIter it = typing.phis.begin(); it != typing.phis.end(); ++it) {
+ graph_->VisitNodeUsesFrom(*it, &widen);
}
+
+ DCHECK(decorator_ == NULL);
+ decorator_ = new (zone()) Decorator(this);
+ graph_->AddDecorator(decorator_);
}
-void Typer::Narrow(Graph* graph, Node* start, MaybeHandle<Context> context) {
- NarrowVisitor typing(this, context);
- graph->VisitNodeUsesFrom(start, &typing);
+void Typer::Narrow(Node* start) {
+ NarrowVisitor typing(this);
+ graph_->VisitNodeUsesFrom(start, &typing);
}
-void Typer::Widen(Graph* graph, Node* start, MaybeHandle<Context> context) {
- WidenVisitor typing(this, context);
- graph->VisitNodeUsesFrom(start, &typing);
+void Typer::Decorator::Decorate(Node* node) {
+ if (OperatorProperties::HasValueOutput(node->op())) {
+ Visitor typing(typer_);
+ Bounds bounds = typing.TypeNode(node);
+ NodeProperties::SetBounds(node, bounds);
+ }
}
-void Typer::Init(Node* node) {
- Visitor typing(this, MaybeHandle<Context>());
- Bounds bounds = typing.TypeNode(node);
- NodeProperties::SetBounds(node, bounds);
+// -----------------------------------------------------------------------------
+
+// Control operators.
+
+Bounds Typer::Visitor::TypeStart(Node* node) {
+ return Bounds(Type::Internal(zone()));
}
// Common operators.
+
Bounds Typer::Visitor::TypeParameter(Node* node) {
return Bounds::Unbounded(zone());
}
@@ -254,39 +288,46 @@ Bounds Typer::Visitor::TypeExternalConstant(Node* node) {
Bounds Typer::Visitor::TypePhi(Node* node) {
int arity = OperatorProperties::GetValueInputCount(node->op());
- Bounds bounds = OperandType(node, 0);
+ Bounds bounds = operand(node, 0);
for (int i = 1; i < arity; ++i) {
- bounds = Bounds::Either(bounds, OperandType(node, i), zone());
+ bounds = Bounds::Either(bounds, operand(node, i), zone());
}
return bounds;
}
Bounds Typer::Visitor::TypeEffectPhi(Node* node) {
- return Bounds(Type::None(zone()));
+ UNREACHABLE();
+ return Bounds();
}
Bounds Typer::Visitor::TypeControlEffect(Node* node) {
- return Bounds(Type::None(zone()));
+ UNREACHABLE();
+ return Bounds();
}
Bounds Typer::Visitor::TypeValueEffect(Node* node) {
- return Bounds(Type::None(zone()));
+ UNREACHABLE();
+ return Bounds();
}
-Bounds Typer::Visitor::TypeFinish(Node* node) { return OperandType(node, 0); }
+Bounds Typer::Visitor::TypeFinish(Node* node) {
+ return operand(node, 0);
+}
Bounds Typer::Visitor::TypeFrameState(Node* node) {
- return Bounds(Type::None(zone()));
+ UNREACHABLE();
+ return Bounds();
}
Bounds Typer::Visitor::TypeStateValues(Node* node) {
- return Bounds(Type::None(zone()));
+ UNREACHABLE();
+ return Bounds();
}
@@ -314,8 +355,8 @@ JS_COMPARE_BINOP_LIST(DEFINE_METHOD)
// JS bitwise operators.
Bounds Typer::Visitor::TypeJSBitwiseOr(Node* node) {
- Bounds left = OperandType(node, 0);
- Bounds right = OperandType(node, 1);
+ Bounds left = operand(node, 0);
+ Bounds right = operand(node, 1);
Type* upper = Type::Union(left.upper, right.upper, zone());
if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
@@ -324,8 +365,8 @@ Bounds Typer::Visitor::TypeJSBitwiseOr(Node* node) {
Bounds Typer::Visitor::TypeJSBitwiseAnd(Node* node) {
- Bounds left = OperandType(node, 0);
- Bounds right = OperandType(node, 1);
+ Bounds left = operand(node, 0);
+ Bounds right = operand(node, 1);
Type* upper = Type::Union(left.upper, right.upper, zone());
if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
@@ -356,8 +397,8 @@ Bounds Typer::Visitor::TypeJSShiftRightLogical(Node* node) {
// JS arithmetic operators.
Bounds Typer::Visitor::TypeJSAdd(Node* node) {
- Bounds left = OperandType(node, 0);
- Bounds right = OperandType(node, 1);
+ Bounds left = operand(node, 0);
+ Bounds right = operand(node, 1);
Type* lower =
left.lower->Is(Type::None()) || right.lower->Is(Type::None()) ?
Type::None(zone()) :
@@ -431,7 +472,7 @@ Bounds Typer::Visitor::TypeJSToName(Node* node) {
Bounds Typer::Visitor::TypeJSToObject(Node* node) {
- return Bounds(Type::None(zone()), Type::Object(zone()));
+ return Bounds(Type::None(zone()), Type::Receiver(zone()));
}
@@ -443,8 +484,8 @@ Bounds Typer::Visitor::TypeJSCreate(Node* node) {
Bounds Typer::Visitor::TypeJSLoadProperty(Node* node) {
- Bounds object = OperandType(node, 0);
- Bounds name = OperandType(node, 1);
+ Bounds object = operand(node, 0);
+ Bounds name = operand(node, 1);
Bounds result = Bounds::Unbounded(zone());
// TODO(rossberg): Use range types and sized array types to filter undefined.
if (object.lower->IsArray() && name.lower->Is(Type::Integral32())) {
@@ -465,12 +506,14 @@ Bounds Typer::Visitor::TypeJSLoadNamed(Node* node) {
Bounds Typer::Visitor::TypeJSStoreProperty(Node* node) {
- return Bounds(Type::None(zone()));
+ UNREACHABLE();
+ return Bounds();
}
Bounds Typer::Visitor::TypeJSStoreNamed(Node* node) {
- return Bounds(Type::None(zone()));
+ UNREACHABLE();
+ return Bounds();
}
@@ -492,9 +535,11 @@ Bounds Typer::Visitor::TypeJSInstanceOf(Node* node) {
// JS context operators.
Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
- Bounds outer = OperandType(node, 0);
- DCHECK(outer.upper->Is(Type::Internal()));
- DCHECK(outer.lower->Equals(outer.upper));
+ Bounds outer = operand(node, 0);
+ DCHECK(outer.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.
+
ContextAccess access = OpParameter<ContextAccess>(node);
Type* context_type = outer.upper;
MaybeHandle<Context> context;
@@ -528,43 +573,44 @@ Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
Bounds Typer::Visitor::TypeJSStoreContext(Node* node) {
- return Bounds(Type::None(zone()));
+ UNREACHABLE();
+ return Bounds();
}
Bounds Typer::Visitor::TypeJSCreateFunctionContext(Node* node) {
- Type* outer = ContextType(node);
+ Type* outer = context_type(node);
return Bounds(Type::Context(outer, zone()));
}
Bounds Typer::Visitor::TypeJSCreateCatchContext(Node* node) {
- Type* outer = ContextType(node);
+ Type* outer = context_type(node);
return Bounds(Type::Context(outer, zone()));
}
Bounds Typer::Visitor::TypeJSCreateWithContext(Node* node) {
- Type* outer = ContextType(node);
+ Type* outer = context_type(node);
return Bounds(Type::Context(outer, zone()));
}
Bounds Typer::Visitor::TypeJSCreateBlockContext(Node* node) {
- Type* outer = ContextType(node);
+ Type* outer = context_type(node);
return Bounds(Type::Context(outer, zone()));
}
Bounds Typer::Visitor::TypeJSCreateModuleContext(Node* node) {
// TODO(rossberg): this is probably incorrect
- Type* outer = ContextType(node);
+ Type* outer = context_type(node);
return Bounds(Type::Context(outer, zone()));
}
Bounds Typer::Visitor::TypeJSCreateGlobalContext(Node* node) {
- Type* outer = ContextType(node);
+ Type* outer = context_type(node);
return Bounds(Type::Context(outer, zone()));
}
@@ -582,7 +628,7 @@ Bounds Typer::Visitor::TypeJSCallConstruct(Node* node) {
Bounds Typer::Visitor::TypeJSCallFunction(Node* node) {
- Bounds fun = OperandType(node, 0);
+ Bounds fun = operand(node, 0);
Type* lower = fun.lower->IsFunction()
? fun.lower->AsFunction()->Result() : Type::None(zone());
Type* upper = fun.upper->IsFunction()
@@ -649,7 +695,7 @@ Bounds Typer::Visitor::TypeNumberModulus(Node* node) {
Bounds Typer::Visitor::TypeNumberToInt32(Node* node) {
- Bounds arg = OperandType(node, 0);
+ Bounds arg = operand(node, 0);
Type* s32 = Type::Signed32(zone());
Type* lower = arg.lower->Is(s32) ? arg.lower : s32;
Type* upper = arg.upper->Is(s32) ? arg.upper : s32;
@@ -658,7 +704,7 @@ Bounds Typer::Visitor::TypeNumberToInt32(Node* node) {
Bounds Typer::Visitor::TypeNumberToUint32(Node* node) {
- Bounds arg = OperandType(node, 0);
+ Bounds arg = operand(node, 0);
Type* u32 = Type::Unsigned32(zone());
Type* lower = arg.lower->Is(u32) ? arg.lower : u32;
Type* upper = arg.upper->Is(u32) ? arg.upper : u32;
@@ -749,12 +795,14 @@ Bounds Typer::Visitor::TypeLoadElement(Node* node) {
Bounds Typer::Visitor::TypeStoreField(Node* node) {
- return Bounds(Type::None());
+ UNREACHABLE();
+ return Bounds();
}
Bounds Typer::Visitor::TypeStoreElement(Node* node) {
- return Bounds(Type::None());
+ UNREACHABLE();
+ return Bounds();
}
@@ -831,25 +879,6 @@ Type* Typer::Visitor::TypeConstant(Handle<Object> value) {
return Type::Constant(value, zone());
}
-
-namespace {
-
-class TyperDecorator : public GraphDecorator {
- public:
- explicit TyperDecorator(Typer* typer) : typer_(typer) {}
- virtual void Decorate(Node* node) { typer_->Init(node); }
-
- private:
- Typer* typer_;
-};
-
-}
-
-
-void Typer::DecorateGraph(Graph* graph) {
- graph->AddDecorator(new (zone()) TyperDecorator(this));
-}
-
}
}
} // namespace v8::internal::compiler
« src/compiler/js-graph.cc ('K') | « src/compiler/typer.h ('k') | src/compiler/verifier.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698