Add iterative primitive type analysis.

This change adds a data-flow pass to statically determine
if a variable contains a primitive type.

It requires building the flow graph and computing reaching
definitions as pre-requisites. The analysis annotates all
VariableProxy nodes with the result.

Review URL: http://codereview.chromium.org/1132005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4224 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f08648dc
...@@ -79,7 +79,8 @@ VariableProxy::VariableProxy(Handle<String> name, ...@@ -79,7 +79,8 @@ VariableProxy::VariableProxy(Handle<String> name,
is_this_(is_this), is_this_(is_this),
inside_with_(inside_with), inside_with_(inside_with),
is_trivial_(false), is_trivial_(false),
reaching_definitions_(NULL) { reaching_definitions_(NULL),
is_primitive_(false) {
// names must be canonicalized for fast equality checks // names must be canonicalized for fast equality checks
ASSERT(name->IsSymbol()); ASSERT(name->IsSymbol());
} }
...@@ -87,7 +88,8 @@ VariableProxy::VariableProxy(Handle<String> name, ...@@ -87,7 +88,8 @@ VariableProxy::VariableProxy(Handle<String> name,
VariableProxy::VariableProxy(bool is_this) VariableProxy::VariableProxy(bool is_this)
: is_this_(is_this), : is_this_(is_this),
reaching_definitions_(NULL) { reaching_definitions_(NULL),
is_primitive_(false) {
} }
...@@ -518,12 +520,18 @@ bool ThisFunction::IsPrimitive() { return false; } ...@@ -518,12 +520,18 @@ bool ThisFunction::IsPrimitive() { return false; }
// The following expression types are not always primitive because we do not // The following expression types are not always primitive because we do not
// have enough information to conclude that they are. // have enough information to conclude that they are.
bool VariableProxy::IsPrimitive() { return false; }
bool Property::IsPrimitive() { return false; } bool Property::IsPrimitive() { return false; }
bool Call::IsPrimitive() { return false; } bool Call::IsPrimitive() { return false; }
bool CallRuntime::IsPrimitive() { return false; } bool CallRuntime::IsPrimitive() { return false; }
// A variable use is not primitive unless the primitive-type analysis
// determines otherwise.
bool VariableProxy::IsPrimitive() {
ASSERT(!is_primitive_ || (var() != NULL && var()->IsStackAllocated()));
return is_primitive_;
}
// The value of a conditional is the value of one of the alternatives. It's // The value of a conditional is the value of one of the alternatives. It's
// always primitive if both alternatives are always primitive. // always primitive if both alternatives are always primitive.
bool Conditional::IsPrimitive() { bool Conditional::IsPrimitive() {
......
...@@ -1078,6 +1078,8 @@ class VariableProxy: public Expression { ...@@ -1078,6 +1078,8 @@ class VariableProxy: public Expression {
virtual bool IsPrimitive(); virtual bool IsPrimitive();
void SetIsPrimitive(bool value) { is_primitive_ = value; }
bool IsVariable(Handle<String> n) { bool IsVariable(Handle<String> n) {
return !is_this() && name().is_identical_to(n); return !is_this() && name().is_identical_to(n);
} }
...@@ -1107,6 +1109,7 @@ class VariableProxy: public Expression { ...@@ -1107,6 +1109,7 @@ class VariableProxy: public Expression {
bool inside_with_; bool inside_with_;
bool is_trivial_; bool is_trivial_;
BitVector* reaching_definitions_; BitVector* reaching_definitions_;
bool is_primitive_;
VariableProxy(Handle<String> name, bool is_this, bool inside_with); VariableProxy(Handle<String> name, bool is_this, bool inside_with);
explicit VariableProxy(bool is_this); explicit VariableProxy(bool is_this);
......
...@@ -100,6 +100,12 @@ static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) { ...@@ -100,6 +100,12 @@ static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) {
builder.body_definitions(), builder.body_definitions(),
variable_count); variable_count);
rd.Compute(); rd.Compute();
TypeAnalyzer ta(builder.postorder(),
builder.body_definitions(),
variable_count,
function->num_parameters());
ta.Compute();
} }
} }
...@@ -503,14 +509,20 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, ...@@ -503,14 +509,20 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
FlowGraphBuilder builder(variable_count); FlowGraphBuilder builder(variable_count);
builder.Build(literal); builder.Build(literal);
if (!builder.HasStackOverflow()) { if (!builder.HasStackOverflow()) {
if (variable_count > 0) { if (variable_count > 0) {
ReachingDefinitions rd(builder.postorder(), ReachingDefinitions rd(builder.postorder(),
builder.body_definitions(), builder.body_definitions(),
variable_count); variable_count);
rd.Compute(); rd.Compute();
TypeAnalyzer ta(builder.postorder(),
builder.body_definitions(),
variable_count,
literal->num_parameters());
ta.Compute();
}
} }
}
#ifdef DEBUG #ifdef DEBUG
if (FLAG_print_graph_text && !builder.HasStackOverflow()) { if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
......
...@@ -1994,4 +1994,56 @@ void ReachingDefinitions::Compute() { ...@@ -1994,4 +1994,56 @@ void ReachingDefinitions::Compute() {
} }
bool TypeAnalyzer::IsPrimitiveDef(int def_num) {
if (def_num < param_count_) return false;
if (def_num < variable_count_) return true;
return body_definitions_->at(def_num - variable_count_)->IsPrimitive();
}
void TypeAnalyzer::Compute() {
bool changed;
int count = 0;
do {
changed = false;
if (FLAG_print_graph_text) {
PrintF("TypeAnalyzer::Compute - iteration %d\n", count++);
}
for (int i = postorder_->length() - 1; i >= 0; --i) {
Node* node = postorder_->at(i);
if (node->IsBlockNode()) {
BlockNode* block = BlockNode::cast(node);
for (int j = 0; j < block->instructions()->length(); j++) {
Expression* expr = block->instructions()->at(j)->AsExpression();
if (expr != NULL) {
// For variable uses: Compute new type from reaching definitions.
VariableProxy* proxy = expr->AsVariableProxy();
if (proxy != NULL && proxy->reaching_definitions() != NULL) {
BitVector* rd = proxy->reaching_definitions();
bool prim_type = true;
// TODO(fsc): A sparse set representation of reaching
// definitions would speed up iterating here.
for (int k = 0; k < rd->length(); k++) {
if (rd->Contains(k) && !IsPrimitiveDef(k)) {
prim_type = false;
break;
}
}
// Reset changed flag if new type information was computed.
if (prim_type != proxy->IsPrimitive()) {
changed = true;
proxy->SetIsPrimitive(prim_type);
}
}
}
}
}
}
} while (changed);
}
} } // namespace v8::internal } } // namespace v8::internal
...@@ -305,6 +305,8 @@ class BlockNode: public Node { ...@@ -305,6 +305,8 @@ class BlockNode: public Node {
bool is_empty() { return instructions_.is_empty(); } bool is_empty() { return instructions_.is_empty(); }
ZoneList<AstNode*>* instructions() { return &instructions_; }
void AddPredecessor(Node* predecessor) { void AddPredecessor(Node* predecessor) {
ASSERT(predecessor_ == NULL && predecessor != NULL); ASSERT(predecessor_ == NULL && predecessor != NULL);
predecessor_ = predecessor; predecessor_ = predecessor;
...@@ -620,6 +622,31 @@ class ReachingDefinitions BASE_EMBEDDED { ...@@ -620,6 +622,31 @@ class ReachingDefinitions BASE_EMBEDDED {
}; };
class TypeAnalyzer BASE_EMBEDDED {
public:
TypeAnalyzer(ZoneList<Node*>* postorder,
ZoneList<Expression*>* body_definitions,
int variable_count,
int param_count)
: postorder_(postorder),
body_definitions_(body_definitions),
variable_count_(variable_count),
param_count_(param_count) {}
void Compute();
private:
// Get the primitity of definition number i. Definitions are numbered
// by the flow graph builder.
bool IsPrimitiveDef(int def_num);
ZoneList<Node*>* postorder_;
ZoneList<Expression*>* body_definitions_;
int variable_count_;
int param_count_;
};
} } // namespace v8::internal } } // namespace v8::internal
......
...@@ -668,7 +668,8 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info, ...@@ -668,7 +668,8 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
Variable* var, Variable* var,
Handle<Object> value, Handle<Object> value,
StaticType* type, StaticType* type,
int num) { int num,
bool is_primitive) {
if (var == NULL) { if (var == NULL) {
PrintLiteralIndented(info, value, true); PrintLiteralIndented(info, value, true);
} else { } else {
...@@ -682,6 +683,8 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info, ...@@ -682,6 +683,8 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
if (num != AstNode::kNoNumber) { if (num != AstNode::kNoNumber) {
pos += OS::SNPrintF(buf + pos, ", num = %d", num); pos += OS::SNPrintF(buf + pos, ", num = %d", num);
} }
pos += OS::SNPrintF(buf + pos,
is_primitive ? ", primitive" : ", non-primitive");
OS::SNPrintF(buf + pos, ")"); OS::SNPrintF(buf + pos, ")");
PrintLiteralIndented(buf.start(), value, true); PrintLiteralIndented(buf.start(), value, true);
} }
...@@ -740,7 +743,8 @@ void AstPrinter::PrintParameters(Scope* scope) { ...@@ -740,7 +743,8 @@ void AstPrinter::PrintParameters(Scope* scope) {
PrintLiteralWithModeIndented("VAR", scope->parameter(i), PrintLiteralWithModeIndented("VAR", scope->parameter(i),
scope->parameter(i)->name(), scope->parameter(i)->name(),
scope->parameter(i)->type(), scope->parameter(i)->type(),
AstNode::kNoNumber); AstNode::kNoNumber,
false);
} }
} }
} }
...@@ -786,7 +790,8 @@ void AstPrinter::VisitDeclaration(Declaration* node) { ...@@ -786,7 +790,8 @@ void AstPrinter::VisitDeclaration(Declaration* node) {
node->proxy()->AsVariable(), node->proxy()->AsVariable(),
node->proxy()->name(), node->proxy()->name(),
node->proxy()->AsVariable()->type(), node->proxy()->AsVariable()->type(),
AstNode::kNoNumber); AstNode::kNoNumber,
node->proxy()->IsPrimitive());
} else { } else {
// function declarations // function declarations
PrintIndented("FUNCTION "); PrintIndented("FUNCTION ");
...@@ -1022,7 +1027,7 @@ void AstPrinter::VisitSlot(Slot* node) { ...@@ -1022,7 +1027,7 @@ void AstPrinter::VisitSlot(Slot* node) {
void AstPrinter::VisitVariableProxy(VariableProxy* node) { void AstPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name(), PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name(),
node->type(), node->num()); node->type(), node->num(), node->IsPrimitive());
Variable* var = node->var(); Variable* var = node->var();
if (var != NULL && var->rewrite() != NULL) { if (var != NULL && var->rewrite() != NULL) {
IndentedScope indent; IndentedScope indent;
......
...@@ -103,7 +103,8 @@ class AstPrinter: public PrettyPrinter { ...@@ -103,7 +103,8 @@ class AstPrinter: public PrettyPrinter {
Variable* var, Variable* var,
Handle<Object> value, Handle<Object> value,
StaticType* type, StaticType* type,
int num); int num,
bool is_primitive);
void PrintLabelsIndented(const char* info, ZoneStringList* labels); void PrintLabelsIndented(const char* info, ZoneStringList* labels);
void inc_indent() { indent_++; } void inc_indent() { indent_++; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment