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,
is_this_(is_this),
inside_with_(inside_with),
is_trivial_(false),
reaching_definitions_(NULL) {
reaching_definitions_(NULL),
is_primitive_(false) {
// names must be canonicalized for fast equality checks
ASSERT(name->IsSymbol());
}
......@@ -87,7 +88,8 @@ VariableProxy::VariableProxy(Handle<String> name,
VariableProxy::VariableProxy(bool is_this)
: is_this_(is_this),
reaching_definitions_(NULL) {
reaching_definitions_(NULL),
is_primitive_(false) {
}
......@@ -518,12 +520,18 @@ bool ThisFunction::IsPrimitive() { return false; }
// The following expression types are not always primitive because we do not
// have enough information to conclude that they are.
bool VariableProxy::IsPrimitive() { return false; }
bool Property::IsPrimitive() { return false; }
bool Call::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
// always primitive if both alternatives are always primitive.
bool Conditional::IsPrimitive() {
......
......@@ -1078,6 +1078,8 @@ class VariableProxy: public Expression {
virtual bool IsPrimitive();
void SetIsPrimitive(bool value) { is_primitive_ = value; }
bool IsVariable(Handle<String> n) {
return !is_this() && name().is_identical_to(n);
}
......@@ -1107,6 +1109,7 @@ class VariableProxy: public Expression {
bool inside_with_;
bool is_trivial_;
BitVector* reaching_definitions_;
bool is_primitive_;
VariableProxy(Handle<String> name, bool is_this, bool inside_with);
explicit VariableProxy(bool is_this);
......
......@@ -100,6 +100,12 @@ static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) {
builder.body_definitions(),
variable_count);
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,
FlowGraphBuilder builder(variable_count);
builder.Build(literal);
if (!builder.HasStackOverflow()) {
if (variable_count > 0) {
ReachingDefinitions rd(builder.postorder(),
builder.body_definitions(),
variable_count);
rd.Compute();
if (!builder.HasStackOverflow()) {
if (variable_count > 0) {
ReachingDefinitions rd(builder.postorder(),
builder.body_definitions(),
variable_count);
rd.Compute();
TypeAnalyzer ta(builder.postorder(),
builder.body_definitions(),
variable_count,
literal->num_parameters());
ta.Compute();
}
}
}
#ifdef DEBUG
if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
......
......@@ -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
......@@ -305,6 +305,8 @@ class BlockNode: public Node {
bool is_empty() { return instructions_.is_empty(); }
ZoneList<AstNode*>* instructions() { return &instructions_; }
void AddPredecessor(Node* predecessor) {
ASSERT(predecessor_ == NULL && predecessor != NULL);
predecessor_ = predecessor;
......@@ -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
......
......@@ -668,7 +668,8 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
Variable* var,
Handle<Object> value,
StaticType* type,
int num) {
int num,
bool is_primitive) {
if (var == NULL) {
PrintLiteralIndented(info, value, true);
} else {
......@@ -682,6 +683,8 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
if (num != AstNode::kNoNumber) {
pos += OS::SNPrintF(buf + pos, ", num = %d", num);
}
pos += OS::SNPrintF(buf + pos,
is_primitive ? ", primitive" : ", non-primitive");
OS::SNPrintF(buf + pos, ")");
PrintLiteralIndented(buf.start(), value, true);
}
......@@ -740,7 +743,8 @@ void AstPrinter::PrintParameters(Scope* scope) {
PrintLiteralWithModeIndented("VAR", scope->parameter(i),
scope->parameter(i)->name(),
scope->parameter(i)->type(),
AstNode::kNoNumber);
AstNode::kNoNumber,
false);
}
}
}
......@@ -786,7 +790,8 @@ void AstPrinter::VisitDeclaration(Declaration* node) {
node->proxy()->AsVariable(),
node->proxy()->name(),
node->proxy()->AsVariable()->type(),
AstNode::kNoNumber);
AstNode::kNoNumber,
node->proxy()->IsPrimitive());
} else {
// function declarations
PrintIndented("FUNCTION ");
......@@ -1022,7 +1027,7 @@ void AstPrinter::VisitSlot(Slot* node) {
void AstPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name(),
node->type(), node->num());
node->type(), node->num(), node->IsPrimitive());
Variable* var = node->var();
if (var != NULL && var->rewrite() != NULL) {
IndentedScope indent;
......
......@@ -103,7 +103,8 @@ class AstPrinter: public PrettyPrinter {
Variable* var,
Handle<Object> value,
StaticType* type,
int num);
int num,
bool is_primitive);
void PrintLabelsIndented(const char* info, ZoneStringList* labels);
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