Rework flow graph construction.

The flow graph has been simplified to remove the special branch, join,
and exit nodes.  All nodes are now basic blocks (possibly empty to
preserve edge-split form) with a distinguished entry and exit block.

Most trivial expressions are not added to the flow graph as
instructions.  The assigned variable analyzer has been changed to
sometimes work right-to-left so that right subexpressions can be
marked as trivial.

The reaching definitions analysis has been temporarily removed, and
the analyses that depended on it (primitivity analysis, dead code
marking) as well.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4307 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 30efbb06
......@@ -749,117 +749,6 @@ bool CompareOperation::IsCritical() {
}
static inline void MarkIfNotLive(Expression* expr, List<AstNode*>* stack) {
if (!expr->is_live()) {
expr->mark_as_live();
stack->Add(expr);
}
}
// Overloaded functions for marking children of live code as live.
void VariableProxy::ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
// A reference to a stack-allocated variable depends on all the
// definitions reaching it.
BitVector* defs = reaching_definitions();
if (defs != NULL) {
ASSERT(var()->IsStackAllocated());
// The first variable_count definitions are the initial parameter and
// local declarations.
for (int i = variable_count; i < defs->length(); i++) {
if (defs->Contains(i)) {
MarkIfNotLive(body_definitions->at(i - variable_count), stack);
}
}
}
}
void Literal::ProcessNonLiveChildren(List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
// Leaf node, no children.
}
void Assignment::ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
Property* prop = target()->AsProperty();
VariableProxy* proxy = target()->AsVariableProxy();
if (prop != NULL) {
if (!prop->key()->IsPropertyName()) MarkIfNotLive(prop->key(), stack);
MarkIfNotLive(prop->obj(), stack);
} else if (proxy == NULL) {
// Must be a reference error.
ASSERT(!target()->IsValidLeftHandSide());
MarkIfNotLive(target(), stack);
} else if (is_compound()) {
// A variable assignment so lhs is an operand to the operation.
MarkIfNotLive(target(), stack);
}
MarkIfNotLive(value(), stack);
}
void Property::ProcessNonLiveChildren(List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
if (!key()->IsPropertyName()) MarkIfNotLive(key(), stack);
MarkIfNotLive(obj(), stack);
}
void Call::ProcessNonLiveChildren(List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
ZoneList<Expression*>* args = arguments();
for (int i = args->length() - 1; i >= 0; i--) {
MarkIfNotLive(args->at(i), stack);
}
MarkIfNotLive(expression(), stack);
}
void UnaryOperation::ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
MarkIfNotLive(expression(), stack);
}
void CountOperation::ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
MarkIfNotLive(expression(), stack);
}
void BinaryOperation::ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
MarkIfNotLive(right(), stack);
MarkIfNotLive(left(), stack);
}
void CompareOperation::ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
MarkIfNotLive(right(), stack);
MarkIfNotLive(left(), stack);
}
// Implementation of a copy visitor. The visitor create a deep copy
// of ast nodes. Nodes that do not require a deep copy are copied
// with the default copy constructor.
......
......@@ -294,19 +294,6 @@ class Expression: public AstNode {
bitfields_ |= NumBitOpsField::encode(num_bit_ops);
}
// Functions used for dead-code elimination. Predicate is true if the
// expression is not dead code.
int is_live() const { return LiveField::decode(bitfields_); }
void mark_as_live() { bitfields_ |= LiveField::encode(true); }
// Mark non-live children as live and push them on a stack for further
// processing.
virtual void ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
}
private:
static const int kMaxNumBitOps = (1 << 5) - 1;
......@@ -319,7 +306,6 @@ class Expression: public AstNode {
class ToInt32Field : public BitField<bool, 2, 1> {};
class NumBitOpsField : public BitField<int, 3, 5> {};
class LoopConditionField: public BitField<bool, 8, 1> {};
class LiveField: public BitField<bool, 9, 1> {};
};
......@@ -907,10 +893,6 @@ class Literal: public Expression {
virtual bool IsTrivial() { return true; }
virtual bool IsPrimitive();
virtual bool IsCritical();
virtual void ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
// Identity testers.
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
......@@ -1118,10 +1100,6 @@ class VariableProxy: public Expression {
virtual bool IsPrimitive();
virtual bool IsCritical();
virtual void ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
void SetIsPrimitive(bool value) { is_primitive_ = value; }
......@@ -1260,10 +1238,6 @@ class Property: public Expression {
virtual bool IsPrimitive();
virtual bool IsCritical();
virtual void ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
Expression* obj() const { return obj_; }
Expression* key() const { return key_; }
......@@ -1299,10 +1273,6 @@ class Call: public Expression {
virtual bool IsPrimitive();
virtual bool IsCritical();
virtual void ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
Expression* expression() const { return expression_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
......@@ -1382,10 +1352,6 @@ class UnaryOperation: public Expression {
virtual bool IsPrimitive();
virtual bool IsCritical();
virtual void ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
Token::Value op() const { return op_; }
Expression* expression() const { return expression_; }
......@@ -1412,10 +1378,6 @@ class BinaryOperation: public Expression {
virtual bool IsPrimitive();
virtual bool IsCritical();
virtual void ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
// True iff the result can be safely overwritten (to avoid allocation).
// False for operations that can return one of their operands.
......@@ -1473,10 +1435,6 @@ class CountOperation: public Expression {
virtual bool IsPrimitive();
virtual bool IsCritical();
virtual void ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
bool is_prefix() const { return is_prefix_; }
bool is_postfix() const { return !is_prefix_; }
......@@ -1510,10 +1468,6 @@ class CompareOperation: public Expression {
virtual bool IsPrimitive();
virtual bool IsCritical();
virtual void ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
Token::Value op() const { return op_; }
Expression* left() const { return left_; }
......@@ -1568,10 +1522,6 @@ class Assignment: public Expression {
virtual bool IsPrimitive();
virtual bool IsCritical();
virtual void ProcessNonLiveChildren(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; }
......
......@@ -90,33 +90,13 @@ static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) {
}
if (FLAG_use_flow_graph) {
int variable_count =
function->num_parameters() + function->scope()->num_stack_slots();
FlowGraphBuilder builder(variable_count);
builder.Build(function);
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,
function->num_parameters());
ta.Compute();
MarkLiveCode(builder.preorder(),
builder.body_definitions(),
variable_count);
}
}
FlowGraphBuilder builder;
FlowGraph* graph = builder.Build(function);
USE(graph);
#ifdef DEBUG
if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
builder.graph()->PrintText(function, builder.postorder());
graph->PrintAsText(function->name());
}
#endif
}
......@@ -499,33 +479,13 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
}
if (FLAG_use_flow_graph) {
int variable_count =
literal->num_parameters() + literal->scope()->num_stack_slots();
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();
TypeAnalyzer ta(builder.postorder(),
builder.body_definitions(),
variable_count,
literal->num_parameters());
ta.Compute();
MarkLiveCode(builder.preorder(),
builder.body_definitions(),
variable_count);
}
}
FlowGraphBuilder builder;
FlowGraph* graph = builder.Build(literal);
USE(graph);
#ifdef DEBUG
if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
builder.graph()->PrintText(literal, builder.postorder());
graph->PrintAsText(literal->name());
}
#endif
}
......
......@@ -138,10 +138,7 @@ class CompilationInfo BASE_EMBEDDED {
// There should always be a function literal, but it may be set after
// construction (for lazy compilation).
FunctionLiteral* function() { return function_; }
void set_function(FunctionLiteral* literal) {
ASSERT(function_ == NULL);
function_ = literal;
}
void set_function(FunctionLiteral* literal) { function_ = literal; }
// Simple accessors.
bool is_eval() { return is_eval_; }
......
......@@ -28,7 +28,6 @@
#include "v8.h"
#include "data-flow.h"
#include "flow-graph.h"
#include "scopes.h"
namespace v8 {
......@@ -621,21 +620,34 @@ void AssignedVariablesAnalyzer::VisitCatchExtensionObject(
void AssignedVariablesAnalyzer::VisitAssignment(Assignment* expr) {
ASSERT(av_.IsEmpty());
if (expr->target()->AsProperty() != NULL) {
// Visit receiver and key of property store and rhs.
Visit(expr->target()->AsProperty()->obj());
ProcessExpression(expr->target()->AsProperty()->key());
ProcessExpression(expr->value());
// There are three kinds of assignments: variable assignments, property
// assignments, and reference errors (invalid left-hand sides).
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
Property* prop = expr->target()->AsProperty();
ASSERT(var == NULL || prop == NULL);
if (var != NULL) {
MarkIfTrivial(expr->value());
Visit(expr->value());
if (expr->is_compound()) {
// Left-hand side occurs also as an rvalue.
MarkIfTrivial(expr->target());
ProcessExpression(expr->target());
}
RecordAssignedVar(var);
} else if (prop != NULL) {
MarkIfTrivial(expr->value());
Visit(expr->value());
if (!prop->key()->IsPropertyName()) {
MarkIfTrivial(prop->key());
ProcessExpression(prop->key());
}
MarkIfTrivial(prop->obj());
ProcessExpression(prop->obj());
// If we have a variable as a receiver in a property store, check if
// we can mark it as trivial.
MarkIfTrivial(expr->target()->AsProperty()->obj());
} else {
Visit(expr->target());
ProcessExpression(expr->value());
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
if (var != NULL) RecordAssignedVar(var);
}
}
......@@ -648,12 +660,12 @@ void AssignedVariablesAnalyzer::VisitThrow(Throw* expr) {
void AssignedVariablesAnalyzer::VisitProperty(Property* expr) {
ASSERT(av_.IsEmpty());
Visit(expr->obj());
ProcessExpression(expr->key());
// In case we have a variable as a receiver, check if we can mark
// it as trivial.
if (!expr->key()->IsPropertyName()) {
MarkIfTrivial(expr->key());
Visit(expr->key());
}
MarkIfTrivial(expr->obj());
ProcessExpression(expr->obj());
}
......@@ -713,25 +725,19 @@ void AssignedVariablesAnalyzer::VisitCountOperation(CountOperation* expr) {
void AssignedVariablesAnalyzer::VisitBinaryOperation(BinaryOperation* expr) {
ASSERT(av_.IsEmpty());
Visit(expr->left());
ProcessExpression(expr->right());
// In case we have a variable on the left side, check if we can mark
// it as trivial.
MarkIfTrivial(expr->right());
Visit(expr->right());
MarkIfTrivial(expr->left());
ProcessExpression(expr->left());
}
void AssignedVariablesAnalyzer::VisitCompareOperation(CompareOperation* expr) {
ASSERT(av_.IsEmpty());
Visit(expr->left());
ProcessExpression(expr->right());
// In case we have a variable on the left side, check if we can mark
// it as trivial.
MarkIfTrivial(expr->right());
Visit(expr->right());
MarkIfTrivial(expr->left());
ProcessExpression(expr->left());
}
......@@ -746,802 +752,4 @@ void AssignedVariablesAnalyzer::VisitDeclaration(Declaration* decl) {
}
int ReachingDefinitions::IndexFor(Variable* var, int variable_count) {
// Parameters are numbered left-to-right from the beginning of the bit
// set. Stack-allocated locals are allocated right-to-left from the end.
ASSERT(var != NULL && var->IsStackAllocated());
Slot* slot = var->slot();
if (slot->type() == Slot::PARAMETER) {
return slot->index();
} else {
return (variable_count - 1) - slot->index();
}
}
void Node::InitializeReachingDefinitions(int definition_count,
List<BitVector*>* variables,
WorkList<Node>* worklist,
bool mark) {
ASSERT(!IsMarkedWith(mark));
rd_.Initialize(definition_count);
MarkWith(mark);
worklist->Insert(this);
}
void BlockNode::InitializeReachingDefinitions(int definition_count,
List<BitVector*>* variables,
WorkList<Node>* worklist,
bool mark) {
ASSERT(!IsMarkedWith(mark));
int instruction_count = instructions_.length();
int variable_count = variables->length();
rd_.Initialize(definition_count);
// The RD_in set for the entry node has a definition for each parameter
// and local.
if (predecessor_ == NULL) {
for (int i = 0; i < variable_count; i++) rd_.rd_in()->Add(i);
}
for (int i = 0; i < instruction_count; i++) {
Expression* expr = instructions_[i]->AsExpression();
if (expr == NULL) continue;
Variable* var = expr->AssignedVariable();
if (var == NULL || !var->IsStackAllocated()) continue;
// All definitions of this variable are killed.
BitVector* def_set =
variables->at(ReachingDefinitions::IndexFor(var, variable_count));
rd_.kill()->Union(*def_set);
// All previously generated definitions are not generated.
rd_.gen()->Subtract(*def_set);
// This one is generated.
rd_.gen()->Add(expr->num());
}
// Add all blocks except the entry node to the worklist.
if (predecessor_ != NULL) {
MarkWith(mark);
worklist->Insert(this);
}
}
void ExitNode::ComputeRDOut(BitVector* result) {
// Should not be the predecessor of any node.
UNREACHABLE();
}
void BlockNode::ComputeRDOut(BitVector* result) {
// All definitions reaching this block ...
*result = *rd_.rd_in();
// ... except those killed by the block ...
result->Subtract(*rd_.kill());
// ... but including those generated by the block.
result->Union(*rd_.gen());
}
void BranchNode::ComputeRDOut(BitVector* result) {
// Branch nodes don't kill or generate definitions.
*result = *rd_.rd_in();
}
void JoinNode::ComputeRDOut(BitVector* result) {
// Join nodes don't kill or generate definitions.
*result = *rd_.rd_in();
}
void ExitNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
// The exit node has no successors so we can just update in place. New
// RD_in is the union over all predecessors.
int definition_count = rd_.rd_in()->length();
rd_.rd_in()->Clear();
BitVector temp(definition_count);
for (int i = 0, len = predecessors_.length(); i < len; i++) {
// Because ComputeRDOut always overwrites temp and its value is
// always read out before calling ComputeRDOut again, we do not
// have to clear it on each iteration of the loop.
predecessors_[i]->ComputeRDOut(&temp);
rd_.rd_in()->Union(temp);
}
}
void BlockNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
// The entry block has no predecessor. Its RD_in does not change.
if (predecessor_ == NULL) return;
BitVector new_rd_in(rd_.rd_in()->length());
predecessor_->ComputeRDOut(&new_rd_in);
if (rd_.rd_in()->Equals(new_rd_in)) return;
// Update RD_in.
*rd_.rd_in() = new_rd_in;
// Add the successor to the worklist if not already present.
if (!successor_->IsMarkedWith(mark)) {
successor_->MarkWith(mark);
worklist->Insert(successor_);
}
}
void BranchNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
BitVector new_rd_in(rd_.rd_in()->length());
predecessor_->ComputeRDOut(&new_rd_in);
if (rd_.rd_in()->Equals(new_rd_in)) return;
// Update RD_in.
*rd_.rd_in() = new_rd_in;
// Add the successors to the worklist if not already present.
if (!successor0_->IsMarkedWith(mark)) {
successor0_->MarkWith(mark);
worklist->Insert(successor0_);
}
if (!successor1_->IsMarkedWith(mark)) {
successor1_->MarkWith(mark);
worklist->Insert(successor1_);
}
}
void JoinNode::UpdateRDIn(WorkList<Node>* worklist, bool mark) {
int definition_count = rd_.rd_in()->length();
BitVector new_rd_in(definition_count);
// New RD_in is the union over all predecessors.
BitVector temp(definition_count);
for (int i = 0, len = predecessors_.length(); i < len; i++) {
predecessors_[i]->ComputeRDOut(&temp);
new_rd_in.Union(temp);
}
if (rd_.rd_in()->Equals(new_rd_in)) return;
// Update RD_in.
*rd_.rd_in() = new_rd_in;
// Add the successor to the worklist if not already present.
if (!successor_->IsMarkedWith(mark)) {
successor_->MarkWith(mark);
worklist->Insert(successor_);
}
}
void Node::PropagateReachingDefinitions(List<BitVector*>* variables) {
// Nothing to do.
}
void BlockNode::PropagateReachingDefinitions(List<BitVector*>* variables) {
// Propagate RD_in from the start of the block to all the variable
// references.
int variable_count = variables->length();
BitVector rd = *rd_.rd_in();
for (int i = 0, len = instructions_.length(); i < len; i++) {
Expression* expr = instructions_[i]->AsExpression();
if (expr == NULL) continue;
// Look for a variable reference to record its reaching definitions.
VariableProxy* proxy = expr->AsVariableProxy();
if (proxy == NULL) {
// Not a VariableProxy? Maybe it's a count operation.
CountOperation* count_operation = expr->AsCountOperation();
if (count_operation != NULL) {
proxy = count_operation->expression()->AsVariableProxy();
}
}
if (proxy == NULL) {
// OK, Maybe it's a compound assignment.
Assignment* assignment = expr->AsAssignment();
if (assignment != NULL && assignment->is_compound()) {
proxy = assignment->target()->AsVariableProxy();
}
}
if (proxy != NULL &&
proxy->var()->IsStackAllocated() &&
!proxy->var()->is_this()) {
// All definitions for this variable.
BitVector* definitions =
variables->at(ReachingDefinitions::IndexFor(proxy->var(),
variable_count));
BitVector* reaching_definitions = new BitVector(*definitions);
// Intersected with all definitions (of any variable) reaching this
// instruction.
reaching_definitions->Intersect(rd);
proxy->set_reaching_definitions(reaching_definitions);
}
// It may instead (or also) be a definition. If so update the running
// value of reaching definitions for the block.
Variable* var = expr->AssignedVariable();
if (var == NULL || !var->IsStackAllocated()) continue;
// All definitions of this variable are killed.
BitVector* def_set =
variables->at(ReachingDefinitions::IndexFor(var, variable_count));
rd.Subtract(*def_set);
// This definition is generated.
rd.Add(expr->num());
}
}
void ReachingDefinitions::Compute() {
// The definitions in the body plus an implicit definition for each
// variable at function entry.
int definition_count = body_definitions_->length() + variable_count_;
int node_count = postorder_->length();
// Step 1: For each stack-allocated variable, identify the set of all its
// definitions.
List<BitVector*> variables;
for (int i = 0; i < variable_count_; i++) {
// Add the initial definition for each variable.
BitVector* initial = new BitVector(definition_count);
initial->Add(i);
variables.Add(initial);
}
for (int i = 0, len = body_definitions_->length(); i < len; i++) {
// Account for each definition in the body as a definition of the
// defined variable.
Variable* var = body_definitions_->at(i)->AssignedVariable();
variables[IndexFor(var, variable_count_)]->Add(i + variable_count_);
}
// Step 2: Compute KILL and GEN for each block node, initialize RD_in for
// all nodes, and mark and add all nodes to the worklist in reverse
// postorder. All nodes should currently have the same mark.
bool mark = postorder_->at(0)->IsMarkedWith(false); // Negation of current.
WorkList<Node> worklist(node_count);
for (int i = node_count - 1; i >= 0; i--) {
postorder_->at(i)->InitializeReachingDefinitions(definition_count,
&variables,
&worklist,
mark);
}
// Step 3: Until the worklist is empty, remove an item compute and update
// its rd_in based on its predecessor's rd_out. If rd_in has changed, add
// all necessary successors to the worklist.
while (!worklist.is_empty()) {
Node* node = worklist.Remove();
node->MarkWith(!mark);
node->UpdateRDIn(&worklist, mark);
}
// Step 4: Based on RD_in for block nodes, propagate reaching definitions
// to all variable uses in the block.
for (int i = 0; i < node_count; i++) {
postorder_->at(i)->PropagateReachingDefinitions(&variables);
}
}
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);
}
void Node::MarkCriticalInstructions(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
}
void BlockNode::MarkCriticalInstructions(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count) {
for (int i = instructions_.length() - 1; i >= 0; i--) {
// Only expressions can appear in the flow graph for now.
Expression* expr = instructions_[i]->AsExpression();
if (expr != NULL && !expr->is_live() &&
(expr->is_loop_condition() || expr->IsCritical())) {
expr->mark_as_live();
expr->ProcessNonLiveChildren(stack, body_definitions, variable_count);
}
}
}
void MarkLiveCode(ZoneList<Node*>* nodes,
ZoneList<Expression*>* body_definitions,
int variable_count) {
List<AstNode*> stack(20);
// Mark the critical AST nodes as live; mark their dependencies and
// add them to the marking stack.
for (int i = nodes->length() - 1; i >= 0; i--) {
nodes->at(i)->MarkCriticalInstructions(&stack, body_definitions,
variable_count);
}
// Continue marking dependencies until no more.
while (!stack.is_empty()) {
// Only expressions can appear in the flow graph for now.
Expression* expr = stack.RemoveLast()->AsExpression();
if (expr != NULL) {
expr->ProcessNonLiveChildren(&stack, body_definitions, variable_count);
}
}
}
#ifdef DEBUG
// Print a textual representation of an instruction in a flow graph. Using
// the AstVisitor is overkill because there is no recursion here. It is
// only used for printing in debug mode.
class TextInstructionPrinter: public AstVisitor {
public:
TextInstructionPrinter() : number_(0) {}
int NextNumber() { return number_; }
void AssignNumber(AstNode* node) { node->set_num(number_++); }
private:
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
int number_;
DISALLOW_COPY_AND_ASSIGN(TextInstructionPrinter);
};
void TextInstructionPrinter::VisitDeclaration(Declaration* decl) {
UNREACHABLE();
}
void TextInstructionPrinter::VisitBlock(Block* stmt) {
PrintF("Block");
}
void TextInstructionPrinter::VisitExpressionStatement(
ExpressionStatement* stmt) {
PrintF("ExpressionStatement");
}
void TextInstructionPrinter::VisitEmptyStatement(EmptyStatement* stmt) {
PrintF("EmptyStatement");
}
void TextInstructionPrinter::VisitIfStatement(IfStatement* stmt) {
PrintF("IfStatement");
}
void TextInstructionPrinter::VisitContinueStatement(ContinueStatement* stmt) {
UNREACHABLE();
}
void TextInstructionPrinter::VisitBreakStatement(BreakStatement* stmt) {
UNREACHABLE();
}
void TextInstructionPrinter::VisitReturnStatement(ReturnStatement* stmt) {
PrintF("return @%d", stmt->expression()->num());
}
void TextInstructionPrinter::VisitWithEnterStatement(WithEnterStatement* stmt) {
PrintF("WithEnterStatement");
}
void TextInstructionPrinter::VisitWithExitStatement(WithExitStatement* stmt) {
PrintF("WithExitStatement");
}
void TextInstructionPrinter::VisitSwitchStatement(SwitchStatement* stmt) {
UNREACHABLE();
}
void TextInstructionPrinter::VisitDoWhileStatement(DoWhileStatement* stmt) {
PrintF("DoWhileStatement");
}
void TextInstructionPrinter::VisitWhileStatement(WhileStatement* stmt) {
PrintF("WhileStatement");
}
void TextInstructionPrinter::VisitForStatement(ForStatement* stmt) {
PrintF("ForStatement");
}
void TextInstructionPrinter::VisitForInStatement(ForInStatement* stmt) {
PrintF("ForInStatement");
}
void TextInstructionPrinter::VisitTryCatchStatement(TryCatchStatement* stmt) {
UNREACHABLE();
}
void TextInstructionPrinter::VisitTryFinallyStatement(
TryFinallyStatement* stmt) {
UNREACHABLE();
}
void TextInstructionPrinter::VisitDebuggerStatement(DebuggerStatement* stmt) {
PrintF("DebuggerStatement");
}
void TextInstructionPrinter::VisitFunctionLiteral(FunctionLiteral* expr) {
PrintF("FunctionLiteral");
}
void TextInstructionPrinter::VisitSharedFunctionInfoLiteral(
SharedFunctionInfoLiteral* expr) {
PrintF("SharedFunctionInfoLiteral");
}
void TextInstructionPrinter::VisitConditional(Conditional* expr) {
PrintF("Conditional");
}
void TextInstructionPrinter::VisitSlot(Slot* expr) {
UNREACHABLE();
}
void TextInstructionPrinter::VisitVariableProxy(VariableProxy* expr) {
Variable* var = expr->AsVariable();
if (var != NULL) {
PrintF("%s", *var->name()->ToCString());
if (var->IsStackAllocated() && expr->reaching_definitions() != NULL) {
expr->reaching_definitions()->Print();
}
} else {
ASSERT(expr->AsProperty() != NULL);
VisitProperty(expr->AsProperty());
}
}
void TextInstructionPrinter::VisitLiteral(Literal* expr) {
expr->handle()->ShortPrint();
}
void TextInstructionPrinter::VisitRegExpLiteral(RegExpLiteral* expr) {
PrintF("RegExpLiteral");
}
void TextInstructionPrinter::VisitObjectLiteral(ObjectLiteral* expr) {
PrintF("ObjectLiteral");
}
void TextInstructionPrinter::VisitArrayLiteral(ArrayLiteral* expr) {
PrintF("ArrayLiteral");
}
void TextInstructionPrinter::VisitCatchExtensionObject(
CatchExtensionObject* expr) {
PrintF("CatchExtensionObject");
}
void TextInstructionPrinter::VisitAssignment(Assignment* expr) {
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
Property* prop = expr->target()->AsProperty();
if (var == NULL && prop == NULL) {
// Throw reference error.
Visit(expr->target());
return;
}
// Print the left-hand side.
if (var != NULL) {
PrintF("%s", *var->name()->ToCString());
} else if (prop != NULL) {
PrintF("@%d", prop->obj()->num());
if (prop->key()->IsPropertyName()) {
PrintF(".");
ASSERT(prop->key()->AsLiteral() != NULL);
prop->key()->AsLiteral()->handle()->Print();
} else {
PrintF("[@%d]", prop->key()->num());
}
}
// Print the operation.
if (expr->is_compound()) {
PrintF(" = ");
// Print the left-hand side again when compound.
if (var != NULL) {
PrintF("@%d", expr->target()->num());
} else {
PrintF("@%d", prop->obj()->num());
if (prop->key()->IsPropertyName()) {
PrintF(".");
ASSERT(prop->key()->AsLiteral() != NULL);
prop->key()->AsLiteral()->handle()->Print();
} else {
PrintF("[@%d]", prop->key()->num());
}
}
// Print the corresponding binary operator.
PrintF(" %s ", Token::String(expr->binary_op()));
} else {
PrintF(" %s ", Token::String(expr->op()));
}
// Print the right-hand side.
PrintF("@%d", expr->value()->num());
if (expr->num() != AstNode::kNoNumber) {
PrintF(" ;; D%d", expr->num());
}
}
void TextInstructionPrinter::VisitThrow(Throw* expr) {
PrintF("throw @%d", expr->exception()->num());
}
void TextInstructionPrinter::VisitProperty(Property* expr) {
if (expr->key()->IsPropertyName()) {
PrintF("@%d.", expr->obj()->num());
ASSERT(expr->key()->AsLiteral() != NULL);
expr->key()->AsLiteral()->handle()->Print();
} else {
PrintF("@%d[@%d]", expr->obj()->num(), expr->key()->num());
}
}
void TextInstructionPrinter::VisitCall(Call* expr) {
PrintF("@%d(", expr->expression()->num());
ZoneList<Expression*>* arguments = expr->arguments();
for (int i = 0, len = arguments->length(); i < len; i++) {
if (i != 0) PrintF(", ");
PrintF("@%d", arguments->at(i)->num());
}
PrintF(")");
}
void TextInstructionPrinter::VisitCallNew(CallNew* expr) {
PrintF("new @%d(", expr->expression()->num());
ZoneList<Expression*>* arguments = expr->arguments();
for (int i = 0, len = arguments->length(); i < len; i++) {
if (i != 0) PrintF(", ");
PrintF("@%d", arguments->at(i)->num());
}
PrintF(")");
}
void TextInstructionPrinter::VisitCallRuntime(CallRuntime* expr) {
PrintF("%s(", *expr->name()->ToCString());
ZoneList<Expression*>* arguments = expr->arguments();
for (int i = 0, len = arguments->length(); i < len; i++) {
if (i != 0) PrintF(", ");
PrintF("@%d", arguments->at(i)->num());
}
PrintF(")");
}
void TextInstructionPrinter::VisitUnaryOperation(UnaryOperation* expr) {
PrintF("%s(@%d)", Token::String(expr->op()), expr->expression()->num());
}
void TextInstructionPrinter::VisitCountOperation(CountOperation* expr) {
if (expr->is_prefix()) {
PrintF("%s@%d", Token::String(expr->op()), expr->expression()->num());
} else {
PrintF("@%d%s", expr->expression()->num(), Token::String(expr->op()));
}
if (expr->num() != AstNode::kNoNumber) {
PrintF(" ;; D%d", expr->num());
}
}
void TextInstructionPrinter::VisitBinaryOperation(BinaryOperation* expr) {
ASSERT(expr->op() != Token::COMMA);
ASSERT(expr->op() != Token::OR);
ASSERT(expr->op() != Token::AND);
PrintF("@%d %s @%d",
expr->left()->num(),
Token::String(expr->op()),
expr->right()->num());
}
void TextInstructionPrinter::VisitCompareOperation(CompareOperation* expr) {
PrintF("@%d %s @%d",
expr->left()->num(),
Token::String(expr->op()),
expr->right()->num());
}
void TextInstructionPrinter::VisitThisFunction(ThisFunction* expr) {
PrintF("ThisFunction");
}
static int node_count = 0;
static int instruction_count = 0;
void Node::AssignNodeNumber() {
set_number(node_count++);
}
void Node::PrintReachingDefinitions() {
if (rd_.rd_in() != NULL) {
ASSERT(rd_.kill() != NULL && rd_.gen() != NULL);
PrintF("RD_in = ");
rd_.rd_in()->Print();
PrintF("\n");
PrintF("RD_kill = ");
rd_.kill()->Print();
PrintF("\n");
PrintF("RD_gen = ");
rd_.gen()->Print();
PrintF("\n");
}
}
void ExitNode::PrintText() {
PrintReachingDefinitions();
PrintF("L%d: Exit\n\n", number());
}
void BlockNode::PrintText() {
PrintReachingDefinitions();
// Print the instructions in the block.
PrintF("L%d: Block\n", number());
TextInstructionPrinter printer;
for (int i = 0, len = instructions_.length(); i < len; i++) {
AstNode* instr = instructions_[i];
// Print a star next to dead instructions.
if (instr->AsExpression() != NULL && instr->AsExpression()->is_live()) {
PrintF(" ");
} else {
PrintF("* ");
}
PrintF("%d ", printer.NextNumber());
printer.Visit(instr);
printer.AssignNumber(instr);
PrintF("\n");
}
PrintF("goto L%d\n\n", successor_->number());
}
void BranchNode::PrintText() {
PrintReachingDefinitions();
PrintF("L%d: Branch\n", number());
PrintF("goto (L%d, L%d)\n\n", successor0_->number(), successor1_->number());
}
void JoinNode::PrintText() {
PrintReachingDefinitions();
PrintF("L%d: Join(", number());
for (int i = 0, len = predecessors_.length(); i < len; i++) {
if (i != 0) PrintF(", ");
PrintF("L%d", predecessors_[i]->number());
}
PrintF(")\ngoto L%d\n\n", successor_->number());
}
void FlowGraph::PrintText(FunctionLiteral* fun, ZoneList<Node*>* postorder) {
PrintF("\n========\n");
PrintF("name = %s\n", *fun->name()->ToCString());
// Number nodes and instructions in reverse postorder.
node_count = 0;
instruction_count = 0;
for (int i = postorder->length() - 1; i >= 0; i--) {
postorder->at(i)->AssignNodeNumber();
}
// Print basic blocks in reverse postorder.
for (int i = postorder->length() - 1; i >= 0; i--) {
postorder->at(i)->PrintText();
}
}
#endif // DEBUG
} } // namespace v8::internal
......@@ -272,65 +272,6 @@ class AssignedVariablesAnalyzer : public AstVisitor {
};
class ReachingDefinitions BASE_EMBEDDED {
public:
ReachingDefinitions(ZoneList<Node*>* postorder,
ZoneList<Expression*>* body_definitions,
int variable_count)
: postorder_(postorder),
body_definitions_(body_definitions),
variable_count_(variable_count) {
}
static int IndexFor(Variable* var, int variable_count);
void Compute();
private:
// A (postorder) list of flow-graph nodes in the body.
ZoneList<Node*>* postorder_;
// A list of all the definitions in the body.
ZoneList<Expression*>* body_definitions_;
int variable_count_;
DISALLOW_COPY_AND_ASSIGN(ReachingDefinitions);
};
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_;
DISALLOW_COPY_AND_ASSIGN(TypeAnalyzer);
};
void MarkLiveCode(ZoneList<Node*>* nodes,
ZoneList<Expression*>* body_definitions,
int variable_count);
} } // namespace v8::internal
......
......@@ -26,232 +26,87 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "flow-graph.h"
#include "scopes.h"
namespace v8 {
namespace internal {
void FlowGraph::AppendInstruction(AstNode* instruction) {
// Add a (non-null) AstNode to the end of the graph fragment.
ASSERT(instruction != NULL);
if (exit()->IsExitNode()) return;
if (!exit()->IsBlockNode()) AppendNode(new BlockNode());
BlockNode::cast(exit())->AddInstruction(instruction);
}
void FlowGraph::AppendNode(Node* node) {
// Add a node to the end of the graph. An empty block is added to
// maintain edge-split form (that no join nodes or exit nodes as
// successors to branch nodes).
ASSERT(node != NULL);
if (exit()->IsExitNode()) return;
if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
AppendNode(new BlockNode());
}
exit()->AddSuccessor(node);
node->AddPredecessor(exit());
exit_ = node;
}
void FlowGraph::AppendGraph(FlowGraph* graph) {
// Add a flow graph fragment to the end of this one. An empty block is
// added to maintain edge-split form (that no join nodes or exit nodes as
// successors to branch nodes).
ASSERT(graph != NULL);
if (exit()->IsExitNode()) return;
Node* node = graph->entry();
if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) {
AppendNode(new BlockNode());
}
exit()->AddSuccessor(node);
node->AddPredecessor(exit());
exit_ = graph->exit();
}
void FlowGraph::Split(BranchNode* branch,
FlowGraph* left,
FlowGraph* right,
JoinNode* join) {
// Add the branch node, left flowgraph, join node.
AppendNode(branch);
AppendGraph(left);
AppendNode(join);
// Splice in the right flowgraph.
right->AppendNode(join);
branch->AddSuccessor(right->entry());
right->entry()->AddPredecessor(branch);
}
void FlowGraph::Loop(JoinNode* join,
FlowGraph* condition,
BranchNode* branch,
FlowGraph* body) {
// Add the join, condition and branch. Add join's predecessors in
// left-to-right order.
AppendNode(join);
body->AppendNode(join);
AppendGraph(condition);
AppendNode(branch);
// Splice in the body flowgraph.
branch->AddSuccessor(body->entry());
body->entry()->AddPredecessor(branch);
}
void ExitNode::Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder) {
preorder->Add(this);
postorder->Add(this);
}
void BlockNode::Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder) {
ASSERT(successor_ != NULL);
void BasicBlock::BuildTraversalOrder(ZoneList<BasicBlock*>* preorder,
ZoneList<BasicBlock*>* postorder,
bool mark) {
if (mark_ == mark) return;
mark_ = mark;
preorder->Add(this);
if (!successor_->IsMarkedWith(mark)) {
successor_->MarkWith(mark);
successor_->Traverse(mark, preorder, postorder);
if (right_successor_ != NULL) {
right_successor_->BuildTraversalOrder(preorder, postorder, mark);
}
postorder->Add(this);
}
void BranchNode::Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder) {
ASSERT(successor0_ != NULL && successor1_ != NULL);
preorder->Add(this);
if (!successor1_->IsMarkedWith(mark)) {
successor1_->MarkWith(mark);
successor1_->Traverse(mark, preorder, postorder);
}
if (!successor0_->IsMarkedWith(mark)) {
successor0_->MarkWith(mark);
successor0_->Traverse(mark, preorder, postorder);
if (left_successor_ != NULL) {
left_successor_->BuildTraversalOrder(preorder, postorder, mark);
}
postorder->Add(this);
}
void JoinNode::Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder) {
ASSERT(successor_ != NULL);
preorder->Add(this);
if (!successor_->IsMarkedWith(mark)) {
successor_->MarkWith(mark);
successor_->Traverse(mark, preorder, postorder);
}
postorder->Add(this);
}
FlowGraph* FlowGraphBuilder::Build(FunctionLiteral* lit) {
// Create new entry and exit nodes. These will not change during
// construction.
entry_ = new BasicBlock(NULL);
exit_ = new BasicBlock(NULL);
// Begin accumulating instructions in the entry block.
current_ = entry_;
void FlowGraphBuilder::Build(FunctionLiteral* lit) {
global_exit_ = new ExitNode();
VisitDeclarations(lit->scope()->declarations());
VisitStatements(lit->body());
if (HasStackOverflow()) return;
// The graph can end with a branch node (if the function ended with a
// loop). Maintain edge-split form (no join nodes or exit nodes as
// successors to branch nodes).
if (graph_.exit()->IsBranchNode()) graph_.AppendNode(new BlockNode());
graph_.AppendNode(global_exit_);
// Build preorder and postorder traversal orders. All the nodes in
// the graph have the same mark flag. For the traversal, use that
// flag's negation. Traversal will flip all the flags.
bool mark = graph_.entry()->IsMarkedWith(false);
graph_.entry()->MarkWith(mark);
graph_.entry()->Traverse(mark, &preorder_, &postorder_);
}
// This function peels off one iteration of a for-loop. The return value
// is either a block statement containing the peeled loop or NULL in case
// there is a stack overflow.
static Statement* PeelForLoop(ForStatement* stmt) {
// Mark this for-statement as processed.
stmt->set_peel_this_loop(false);
// Create new block containing the init statement of the for-loop and
// an if-statement containing the peeled iteration and the original
// loop without the init-statement.
Block* block = new Block(NULL, 2, false);
if (stmt->init() != NULL) {
Statement* init = stmt->init();
// The init statement gets the statement position of the for-loop
// to make debugging of peeled loops possible.
init->set_statement_pos(stmt->statement_pos());
block->AddStatement(init);
// In the event of stack overflow or failure to handle a syntactic
// construct, return an invalid flow graph.
if (HasStackOverflow()) return new FlowGraph(NULL, NULL);
// If current is not the exit, add a link to the exit.
if (current_ != exit_) {
// If current already has a successor (i.e., will be a branch node) and
// if the exit already has a predecessor, insert an empty block to
// maintain edge split form.
if (current_->HasSuccessor() && exit_->HasPredecessor()) {
current_ = new BasicBlock(current_);
}
Literal* undefined = new Literal(Factory::undefined_value());
current_->AddInstruction(new ReturnStatement(undefined));
exit_->AddPredecessor(current_);
}
// Copy the condition.
CopyAstVisitor copy_visitor;
Expression* cond_copy = stmt->cond() != NULL
? copy_visitor.DeepCopyExpr(stmt->cond())
: new Literal(Factory::true_value());
if (copy_visitor.HasStackOverflow()) return NULL;
// Construct a block with the peeled body and the rest of the for-loop.
Statement* body_copy = copy_visitor.DeepCopyStmt(stmt->body());
if (copy_visitor.HasStackOverflow()) return NULL;
Statement* next_copy = stmt->next() != NULL
? copy_visitor.DeepCopyStmt(stmt->next())
: new EmptyStatement();
if (copy_visitor.HasStackOverflow()) return NULL;
FlowGraph* graph = new FlowGraph(entry_, exit_);
bool mark = !entry_->GetMark();
entry_->BuildTraversalOrder(graph->preorder(), graph->postorder(), mark);
Block* peeled_body = new Block(NULL, 3, false);
peeled_body->AddStatement(body_copy);
peeled_body->AddStatement(next_copy);
peeled_body->AddStatement(stmt);
// Remove the duplicated init statement from the for-statement.
stmt->set_init(NULL);
// Create new test at the top and add it to the newly created block.
IfStatement* test = new IfStatement(cond_copy,
peeled_body,
new EmptyStatement());
block->AddStatement(test);
return block;
}
void FlowGraphBuilder::VisitStatements(ZoneList<Statement*>* stmts) {
for (int i = 0, len = stmts->length(); i < len; i++) {
stmts->at(i) = ProcessStatement(stmts->at(i));
#ifdef DEBUG
// Number the nodes in reverse postorder.
int n = 0;
for (int i = graph->postorder()->length() - 1; i >= 0; --i) {
graph->postorder()->at(i)->set_number(n++);
}
}
#endif
Statement* FlowGraphBuilder::ProcessStatement(Statement* stmt) {
if (FLAG_loop_peeling &&
stmt->AsForStatement() != NULL &&
stmt->AsForStatement()->peel_this_loop()) {
Statement* tmp_stmt = PeelForLoop(stmt->AsForStatement());
if (tmp_stmt == NULL) {
SetStackOverflow();
} else {
stmt = tmp_stmt;
}
}
Visit(stmt);
return stmt;
return graph;
}
void FlowGraphBuilder::VisitDeclaration(Declaration* decl) {
UNREACHABLE();
Variable* var = decl->proxy()->AsVariable();
Slot* slot = var->slot();
// We allow only declarations that do not require code generation.
// The following all require code generation: global variables and
// functions, variables with slot type LOOKUP, declarations with
// mode CONST, and functions.
if (var->is_global() ||
(slot != NULL && slot->type() == Slot::LOOKUP) ||
decl->mode() == Variable::CONST ||
decl->fun() != NULL) {
// Here and in the rest of the flow graph builder we indicate an
// unsupported syntactic construct by setting the stack overflow
// flag on the visitor. This causes bailout of the visitor.
SetStackOverflow();
}
}
......@@ -271,21 +126,24 @@ void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) {
// Build a diamond in the flow graph. First accumulate the instructions
// of the test in the current basic block.
Visit(stmt->condition());
BranchNode* branch = new BranchNode();
FlowGraph original = graph_;
graph_ = FlowGraph::Empty();
stmt->set_then_statement(ProcessStatement(stmt->then_statement()));
// Remember the branch node and accumulate the true branch as its left
// successor. This relies on the successors being added left to right.
BasicBlock* branch = current_;
current_ = new BasicBlock(branch);
Visit(stmt->then_statement());
FlowGraph left = graph_;
graph_ = FlowGraph::Empty();
stmt->set_else_statement(ProcessStatement(stmt->else_statement()));
// Construct a join node and then accumulate the false branch in a fresh
// successor of the branch node.
BasicBlock* join = new BasicBlock(current_);
current_ = new BasicBlock(branch);
Visit(stmt->else_statement());
join->AddPredecessor(current_);
if (HasStackOverflow()) return;
JoinNode* join = new JoinNode();
original.Split(branch, &left, &graph_, join);
graph_ = original;
current_ = join;
}
......@@ -330,23 +188,26 @@ void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) {
if (stmt->init() != NULL) stmt->set_init(ProcessStatement(stmt->init()));
// Build a loop in the flow graph. First accumulate the instructions of
// the initializer in the current basic block.
if (stmt->init() != NULL) Visit(stmt->init());
JoinNode* join = new JoinNode();
FlowGraph original = graph_;
graph_ = FlowGraph::Empty();
// Create a new basic block for the test. This will be the join node.
BasicBlock* join = new BasicBlock(current_);
current_ = join;
if (stmt->cond() != NULL) Visit(stmt->cond());
BranchNode* branch = new BranchNode();
FlowGraph condition = graph_;
graph_ = FlowGraph::Empty();
stmt->set_body(ProcessStatement(stmt->body()));
// The current node is the branch node. Create a new basic block to begin
// the body.
BasicBlock* branch = current_;
current_ = new BasicBlock(branch);
Visit(stmt->body());
if (stmt->next() != NULL) Visit(stmt->next());
if (stmt->next() != NULL) stmt->set_next(ProcessStatement(stmt->next()));
if (HasStackOverflow()) return;
original.Loop(join, &condition, branch, &graph_);
graph_ = original;
// Add the backward edge from the end of the body and continue with the
// false arm of the branch.
join->AddPredecessor(current_);
current_ = new BasicBlock(branch);
}
......@@ -387,17 +248,18 @@ void FlowGraphBuilder::VisitConditional(Conditional* expr) {
void FlowGraphBuilder::VisitSlot(Slot* expr) {
// Slots do not appear in the AST.
UNREACHABLE();
}
void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
graph_.AppendInstruction(expr);
current_->AddInstruction(expr);
}
void FlowGraphBuilder::VisitLiteral(Literal* expr) {
graph_.AppendInstruction(expr);
current_->AddInstruction(expr);
}
......@@ -422,29 +284,30 @@ void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
void FlowGraphBuilder::VisitAssignment(Assignment* expr) {
// There are three basic kinds of assignment: variable assignments,
// property assignments, and invalid left-hand sides (which are translated
// to "throw ReferenceError" by the parser).
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
Property* prop = expr->target()->AsProperty();
// Left-hand side can be a variable or property (or reference error) but
// not both.
ASSERT(var == NULL || prop == NULL);
if (var != NULL) {
if (expr->is_compound()) Visit(expr->target());
Visit(expr->value());
if (var->IsStackAllocated()) {
// The first definition in the body is numbered n, where n is the
// number of parameters and stack-allocated locals.
expr->set_num(body_definitions_.length() + variable_count_);
body_definitions_.Add(expr);
if (expr->is_compound() && !expr->target()->IsTrivial()) {
Visit(expr->target());
}
if (!expr->value()->IsTrivial()) Visit(expr->value());
current_->AddInstruction(expr);
} else if (prop != NULL) {
Visit(prop->obj());
if (!prop->key()->IsPropertyName()) Visit(prop->key());
Visit(expr->value());
}
if (!prop->obj()->IsTrivial()) Visit(prop->obj());
if (!prop->key()->IsPropertyName() && !prop->key()->IsTrivial()) {
Visit(prop->key());
}
if (!expr->value()->IsTrivial()) Visit(expr->value());
current_->AddInstruction(expr);
if (HasStackOverflow()) return;
graph_.AppendInstruction(expr);
} else {
Visit(expr->target());
}
}
......@@ -454,23 +317,18 @@ void FlowGraphBuilder::VisitThrow(Throw* expr) {
void FlowGraphBuilder::VisitProperty(Property* expr) {
Visit(expr->obj());
if (!expr->key()->IsPropertyName()) Visit(expr->key());
if (HasStackOverflow()) return;
graph_.AppendInstruction(expr);
if (!expr->obj()->IsTrivial()) Visit(expr->obj());
if (!expr->key()->IsPropertyName() && !expr->key()->IsTrivial()) {
Visit(expr->key());
}
current_->AddInstruction(expr);
}
void FlowGraphBuilder::VisitCall(Call* expr) {
Visit(expr->expression());
ZoneList<Expression*>* arguments = expr->arguments();
for (int i = 0, len = arguments->length(); i < len; i++) {
Visit(arguments->at(i));
}
if (HasStackOverflow()) return;
graph_.AppendInstruction(expr);
VisitExpressions(expr->arguments());
current_->AddInstruction(expr);
}
......@@ -497,8 +355,7 @@ void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
case Token::ADD:
case Token::SUB:
Visit(expr->expression());
if (HasStackOverflow()) return;
graph_.AppendInstruction(expr);
current_->AddInstruction(expr);
break;
default:
......@@ -509,16 +366,7 @@ void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) {
Visit(expr->expression());
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
if (var != NULL && var->IsStackAllocated()) {
// The first definition in the body is numbered n, where n is the number
// of parameters and stack-allocated locals.
expr->set_num(body_definitions_.length() + variable_count_);
body_definitions_.Add(expr);
}
if (HasStackOverflow()) return;
graph_.AppendInstruction(expr);
current_->AddInstruction(expr);
}
......@@ -534,17 +382,16 @@ void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
case Token::BIT_XOR:
case Token::BIT_AND:
case Token::SHL:
case Token::SAR:
case Token::SHR:
case Token::ADD:
case Token::SUB:
case Token::MUL:
case Token::DIV:
case Token::MOD:
case Token::SAR:
Visit(expr->left());
Visit(expr->right());
if (HasStackOverflow()) return;
graph_.AppendInstruction(expr);
if (!expr->left()->IsTrivial()) Visit(expr->left());
if (!expr->right()->IsTrivial()) Visit(expr->right());
current_->AddInstruction(expr);
break;
default:
......@@ -568,10 +415,9 @@ void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
case Token::GT:
case Token::LTE:
case Token::GTE:
Visit(expr->left());
Visit(expr->right());
if (HasStackOverflow()) return;
graph_.AppendInstruction(expr);
if (!expr->left()->IsTrivial()) Visit(expr->left());
if (!expr->right()->IsTrivial()) Visit(expr->right());
current_->AddInstruction(expr);
break;
default:
......@@ -585,4 +431,335 @@ void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) {
}
#ifdef DEBUG
// Print a textual representation of an instruction in a flow graph. Using
// the AstVisitor is overkill because there is no recursion here. It is
// however only used for printing in debug mode.
class InstructionPrinter: public AstVisitor {
public:
InstructionPrinter() {}
private:
// Overridden from the base class.
virtual void VisitExpressions(ZoneList<Expression*>* exprs);
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
DISALLOW_COPY_AND_ASSIGN(InstructionPrinter);
};
static void PrintSubexpression(Expression* expr) {
if (!expr->IsTrivial()) {
PrintF("@%d", expr->num());
} else if (expr->AsLiteral() != NULL) {
expr->AsLiteral()->handle()->Print();
} else if (expr->AsVariableProxy() != NULL) {
PrintF("%s", *expr->AsVariableProxy()->name()->ToCString());
} else {
UNREACHABLE();
}
}
void InstructionPrinter::VisitExpressions(ZoneList<Expression*>* exprs) {
for (int i = 0; i < exprs->length(); ++i) {
if (i != 0) PrintF(", ");
PrintF("@%d", exprs->at(i)->num());
}
}
// We only define printing functions for the node types that can occur as
// instructions in a flow graph. The rest are unreachable.
void InstructionPrinter::VisitDeclaration(Declaration* decl) {
UNREACHABLE();
}
void InstructionPrinter::VisitBlock(Block* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitExpressionStatement(ExpressionStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitEmptyStatement(EmptyStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitIfStatement(IfStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitContinueStatement(ContinueStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitBreakStatement(BreakStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitReturnStatement(ReturnStatement* stmt) {
PrintF("return ");
PrintSubexpression(stmt->expression());
}
void InstructionPrinter::VisitWithEnterStatement(WithEnterStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitWithExitStatement(WithExitStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitSwitchStatement(SwitchStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitDoWhileStatement(DoWhileStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitWhileStatement(WhileStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitForStatement(ForStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitForInStatement(ForInStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitTryCatchStatement(TryCatchStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitDebuggerStatement(DebuggerStatement* stmt) {
UNREACHABLE();
}
void InstructionPrinter::VisitFunctionLiteral(FunctionLiteral* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitSharedFunctionInfoLiteral(
SharedFunctionInfoLiteral* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitConditional(Conditional* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitSlot(Slot* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitVariableProxy(VariableProxy* expr) {
Variable* var = expr->AsVariable();
if (var != NULL) {
PrintF("%s", *var->name()->ToCString());
} else {
ASSERT(expr->AsProperty() != NULL);
VisitProperty(expr->AsProperty());
}
}
void InstructionPrinter::VisitLiteral(Literal* expr) {
expr->handle()->Print();
}
void InstructionPrinter::VisitRegExpLiteral(RegExpLiteral* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitObjectLiteral(ObjectLiteral* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitArrayLiteral(ArrayLiteral* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitCatchExtensionObject(
CatchExtensionObject* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitAssignment(Assignment* expr) {
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
Property* prop = expr->target()->AsProperty();
// Print the left-hand side.
Visit(expr->target());
if (var == NULL && prop == NULL) return; // Throw reference error.
PrintF(" = ");
// For compound assignments, print the left-hand side again and the
// corresponding binary operator.
if (expr->is_compound()) {
PrintSubexpression(expr->target());
PrintF(" %s ", Token::String(expr->binary_op()));
}
// Print the right-hand side.
PrintSubexpression(expr->value());
}
void InstructionPrinter::VisitThrow(Throw* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitProperty(Property* expr) {
PrintSubexpression(expr->obj());
if (expr->key()->IsPropertyName()) {
PrintF(".");
ASSERT(expr->key()->AsLiteral() != NULL);
expr->key()->AsLiteral()->handle()->Print();
} else {
PrintF("[");
PrintSubexpression(expr->key());
PrintF("]");
}
}
void InstructionPrinter::VisitCall(Call* expr) {
PrintF("@%d(", expr->expression()->num());
VisitExpressions(expr->arguments());
PrintF(")");
}
void InstructionPrinter::VisitCallNew(CallNew* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitCallRuntime(CallRuntime* expr) {
UNREACHABLE();
}
void InstructionPrinter::VisitUnaryOperation(UnaryOperation* expr) {
PrintF("%s(@%d)", Token::String(expr->op()), expr->expression()->num());
}
void InstructionPrinter::VisitCountOperation(CountOperation* expr) {
if (expr->is_prefix()) {
PrintF("%s@%d", Token::String(expr->op()), expr->expression()->num());
} else {
PrintF("@%d%s", expr->expression()->num(), Token::String(expr->op()));
}
}
void InstructionPrinter::VisitBinaryOperation(BinaryOperation* expr) {
PrintSubexpression(expr->left());
PrintF(" %s ", Token::String(expr->op()));
PrintSubexpression(expr->right());
}
void InstructionPrinter::VisitCompareOperation(CompareOperation* expr) {
PrintSubexpression(expr->left());
PrintF(" %s ", Token::String(expr->op()));
PrintSubexpression(expr->right());
}
void InstructionPrinter::VisitThisFunction(ThisFunction* expr) {
UNREACHABLE();
}
int BasicBlock::PrintAsText(int instruction_number) {
// Print a label for all blocks except the entry.
if (HasPredecessor()) {
PrintF("L%d:", number());
}
// Number and print the instructions. Since AST child nodes are visited
// before their parents, the parent nodes can refer to them by number.
InstructionPrinter printer;
for (int i = 0; i < instructions_.length(); ++i) {
PrintF("\n%d ", instruction_number);
instructions_[i]->set_num(instruction_number++);
printer.Visit(instructions_[i]);
}
// If this is the exit, print "exit". If there is a single successor,
// print "goto" successor on a separate line. If there are two
// successors, print "goto" successor on the same line as the last
// instruction in the block. There is a blank line between blocks (and
// after the last one).
if (left_successor_ == NULL) {
PrintF("\nexit\n\n");
} else if (right_successor_ == NULL) {
PrintF("\ngoto L%d\n\n", left_successor_->number());
} else {
PrintF(", goto (L%d, L%d)\n\n",
left_successor_->number(),
right_successor_->number());
}
return instruction_number;
}
void FlowGraph::PrintAsText(Handle<String> name) {
PrintF("\n==== name = \"%s\" ====\n", *name->ToCString());
// Print nodes in reverse postorder. Note that AST node numbers are used
// during printing of instructions and thus their current values are
// destroyed.
int number = 0;
for (int i = postorder_.length() - 1; i >= 0; --i) {
number = postorder_[i]->PrintAsText(number);
}
}
#endif // DEBUG
} } // namespace v8::internal
......@@ -36,339 +36,140 @@
namespace v8 {
namespace internal {
// Flow-graph nodes.
class Node: public ZoneObject {
public:
Node() : number_(-1), mark_(false) {}
virtual ~Node() {}
virtual bool IsExitNode() { return false; }
virtual bool IsBlockNode() { return false; }
virtual bool IsBranchNode() { return false; }
virtual bool IsJoinNode() { return false; }
virtual void AddPredecessor(Node* predecessor) = 0;
virtual void AddSuccessor(Node* successor) = 0;
bool IsMarkedWith(bool mark) { return mark_ == mark; }
void MarkWith(bool mark) { mark_ = mark; }
// Perform a depth first search and record preorder and postorder
// traversal orders.
virtual void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder) = 0;
int number() { return number_; }
void set_number(int number) { number_ = number; }
// Functions used by data-flow analyses.
virtual void InitializeReachingDefinitions(int definition_count,
List<BitVector*>* variables,
WorkList<Node>* worklist,
bool mark);
virtual void ComputeRDOut(BitVector* result) = 0;
virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark) = 0;
virtual void PropagateReachingDefinitions(List<BitVector*>* variables);
// Functions used by dead-code elimination.
virtual void MarkCriticalInstructions(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
#ifdef DEBUG
void AssignNodeNumber();
void PrintReachingDefinitions();
virtual void PrintText() = 0;
#endif
protected:
ReachingDefinitionsData rd_;
private:
int number_;
bool mark_;
DISALLOW_COPY_AND_ASSIGN(Node);
};
// An exit node has a arbitrarily many predecessors and no successors.
class ExitNode: public Node {
// The nodes of a flow graph are basic blocks. Basic blocks consist of
// instructions represented as pointers to AST nodes in the order that they
// would be visited by the code generator. A block can have arbitrarily many
// (even zero) predecessors and up to two successors. Blocks with multiple
// predecessors are "join nodes" and blocks with multiple successors are
// "branch nodes". A block can be both a branch and a join node.
//
// Flow graphs are in edge split form: a branch node is never the
// predecessor of a merge node. Empty basic blocks are inserted to maintain
// edge split form.
class BasicBlock: public ZoneObject {
public:
ExitNode() : predecessors_(4) {}
// Construct a basic block with a given predecessor. NULL indicates no
// predecessor or that the predecessor will be set later.
explicit BasicBlock(BasicBlock* predecessor)
: predecessors_(2),
instructions_(8),
left_successor_(NULL),
right_successor_(NULL),
mark_(false) {
if (predecessor != NULL) AddPredecessor(predecessor);
}
virtual bool IsExitNode() { return true; }
bool HasPredecessor() { return !predecessors_.is_empty(); }
bool HasSuccessor() { return left_successor_ != NULL; }
virtual void AddPredecessor(Node* predecessor) {
// Add a given basic block as a predecessor of this block. This function
// also adds this block as a successor of the given block.
void AddPredecessor(BasicBlock* predecessor) {
ASSERT(predecessor != NULL);
predecessors_.Add(predecessor);
predecessor->AddSuccessor(this);
}
virtual void AddSuccessor(Node* successor) { UNREACHABLE(); }
virtual void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder);
virtual void ComputeRDOut(BitVector* result);
virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
#ifdef DEBUG
virtual void PrintText();
#endif
private:
ZoneList<Node*> predecessors_;
DISALLOW_COPY_AND_ASSIGN(ExitNode);
};
// Block nodes have a single successor and predecessor and a list of
// instructions.
class BlockNode: public Node {
public:
BlockNode() : predecessor_(NULL), successor_(NULL), instructions_(4) {}
static BlockNode* cast(Node* node) {
ASSERT(node->IsBlockNode());
return reinterpret_cast<BlockNode*>(node);
}
virtual bool IsBlockNode() { return true; }
bool is_empty() { return instructions_.is_empty(); }
ZoneList<AstNode*>* instructions() { return &instructions_; }
virtual void AddPredecessor(Node* predecessor) {
ASSERT(predecessor_ == NULL && predecessor != NULL);
predecessor_ = predecessor;
}
virtual void AddSuccessor(Node* successor) {
ASSERT(successor_ == NULL && successor != NULL);
successor_ = successor;
}
// Add an instruction to the end of this block. The block must be "open"
// by not having a successor yet.
void AddInstruction(AstNode* instruction) {
ASSERT(!HasSuccessor() && instruction != NULL);
instructions_.Add(instruction);
}
virtual void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder);
virtual void InitializeReachingDefinitions(int definition_count,
List<BitVector*>* variables,
WorkList<Node>* worklist,
bool mark);
virtual void ComputeRDOut(BitVector* result);
virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
virtual void PropagateReachingDefinitions(List<BitVector*>* variables);
virtual void MarkCriticalInstructions(
List<AstNode*>* stack,
ZoneList<Expression*>* body_definitions,
int variable_count);
// Perform a depth-first traversal of graph rooted at this node,
// accumulating pre- and postorder traversal orders. Visited nodes are
// marked with mark.
void BuildTraversalOrder(ZoneList<BasicBlock*>* preorder,
ZoneList<BasicBlock*>* postorder,
bool mark);
bool GetMark() { return mark_; }
#ifdef DEBUG
virtual void PrintText();
// In debug mode, blocks are numbered in reverse postorder to help with
// printing.
int number() { return number_; }
void set_number(int n) { number_ = n; }
// Print a basic block, given the number of the first instruction.
// Returns the next number after the number of the last instruction.
int PrintAsText(int instruction_number);
#endif
private:
Node* predecessor_;
Node* successor_;
ZoneList<AstNode*> instructions_;
DISALLOW_COPY_AND_ASSIGN(BlockNode);
};
// Branch nodes have a single predecessor and a pair of successors.
class BranchNode: public Node {
public:
BranchNode() : predecessor_(NULL), successor0_(NULL), successor1_(NULL) {}
virtual bool IsBranchNode() { return true; }
virtual void AddPredecessor(Node* predecessor) {
ASSERT(predecessor_ == NULL && predecessor != NULL);
predecessor_ = predecessor;
}
virtual void AddSuccessor(Node* successor) {
ASSERT(successor1_ == NULL && successor != NULL);
if (successor0_ == NULL) {
successor0_ = successor;
// Add a given basic block as successor to this block. This function does
// not add this block as a predecessor of the given block so as to avoid
// circularity.
void AddSuccessor(BasicBlock* successor) {
ASSERT(right_successor_ == NULL && successor != NULL);
if (HasSuccessor()) {
right_successor_ = successor;
} else {
successor1_ = successor;
left_successor_ = successor;
}
}
virtual void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder);
virtual void ComputeRDOut(BitVector* result);
virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
#ifdef DEBUG
virtual void PrintText();
#endif
private:
Node* predecessor_;
Node* successor0_;
Node* successor1_;
DISALLOW_COPY_AND_ASSIGN(BranchNode);
};
// Join nodes have arbitrarily many predecessors and a single successor.
class JoinNode: public Node {
public:
JoinNode() : predecessors_(2), successor_(NULL) {}
static JoinNode* cast(Node* node) {
ASSERT(node->IsJoinNode());
return reinterpret_cast<JoinNode*>(node);
}
virtual bool IsJoinNode() { return true; }
virtual void AddPredecessor(Node* predecessor) {
ASSERT(predecessor != NULL);
predecessors_.Add(predecessor);
}
virtual void AddSuccessor(Node* successor) {
ASSERT(successor_ == NULL && successor != NULL);
successor_ = successor;
}
virtual void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder);
ZoneList<BasicBlock*> predecessors_;
ZoneList<AstNode*> instructions_;
BasicBlock* left_successor_;
BasicBlock* right_successor_;
virtual void ComputeRDOut(BitVector* result);
virtual void UpdateRDIn(WorkList<Node>* worklist, bool mark);
// Support for graph traversal. Before traversal, all nodes in the graph
// have the same mark (true or false). Traversal marks already-visited
// nodes with the opposite mark. After traversal, all nodes again have
// the same mark. Traversal of the same graph is not reentrant.
bool mark_;
#ifdef DEBUG
virtual void PrintText();
int number_;
#endif
private:
ZoneList<Node*> predecessors_;
Node* successor_;
DISALLOW_COPY_AND_ASSIGN(JoinNode);
DISALLOW_COPY_AND_ASSIGN(BasicBlock);
};
// Flow graphs have a single entry and single exit. The empty flowgraph is
// represented by both entry and exit being NULL.
class FlowGraph BASE_EMBEDDED {
// A flow graph has distinguished entry and exit blocks. The entry block is
// the only one with no predecessors and the exit block is the only one with
// no successors.
class FlowGraph: public ZoneObject {
public:
static FlowGraph Empty() {
FlowGraph graph;
graph.entry_ = new BlockNode();
graph.exit_ = graph.entry_;
return graph;
FlowGraph(BasicBlock* entry, BasicBlock* exit)
: entry_(entry), exit_(exit), preorder_(8), postorder_(8) {
}
bool is_empty() const {
return entry_ == exit_ && BlockNode::cast(entry_)->is_empty();
}
Node* entry() const { return entry_; }
Node* exit() const { return exit_; }
// Add a single instruction to the end of this flowgraph.
void AppendInstruction(AstNode* instruction);
// Add a single node to the end of this flow graph.
void AppendNode(Node* node);
// Add a flow graph fragment to the end of this one.
void AppendGraph(FlowGraph* graph);
// Concatenate an if-then-else flow-graph to this one. Control is split
// and merged, so the graph remains single-entry, single-exit.
void Split(BranchNode* branch,
FlowGraph* left,
FlowGraph* right,
JoinNode* merge);
// Concatenate a forward loop (e.g., while or for loop) flow-graph to this
// one. Control is split by the condition and merged back from the back
// edge at end of the body to the beginning of the condition. The single
// (free) exit of the result graph is the right (false) arm of the branch
// node.
void Loop(JoinNode* merge,
FlowGraph* condition,
BranchNode* branch,
FlowGraph* body);
ZoneList<BasicBlock*>* preorder() { return &preorder_; }
ZoneList<BasicBlock*>* postorder() { return &postorder_; }
#ifdef DEBUG
void PrintText(FunctionLiteral* fun, ZoneList<Node*>* postorder);
void PrintAsText(Handle<String> name);
#endif
private:
FlowGraph() : entry_(NULL), exit_(NULL) {}
Node* entry_;
Node* exit_;
BasicBlock* entry_;
BasicBlock* exit_;
ZoneList<BasicBlock*> preorder_;
ZoneList<BasicBlock*> postorder_;
};
// Construct a flow graph from a function literal. Build pre- and postorder
// traversal orders as a byproduct.
// The flow graph builder walks the AST adding reachable AST nodes to the
// flow graph as instructions. It remembers the entry and exit nodes of the
// graph, and keeps a pointer to the current block being constructed.
class FlowGraphBuilder: public AstVisitor {
public:
explicit FlowGraphBuilder(int variable_count)
: graph_(FlowGraph::Empty()),
global_exit_(NULL),
preorder_(4),
postorder_(4),
variable_count_(variable_count),
body_definitions_(4) {
}
void Build(FunctionLiteral* lit);
FlowGraphBuilder() {}
FlowGraph* graph() { return &graph_; }
ZoneList<Node*>* preorder() { return &preorder_; }
ZoneList<Node*>* postorder() { return &postorder_; }
ZoneList<Expression*>* body_definitions() { return &body_definitions_; }
FlowGraph* Build(FunctionLiteral* lit);
private:
ExitNode* global_exit() { return global_exit_; }
// Helpers to allow tranforming the ast during flow graph construction.
void VisitStatements(ZoneList<Statement*>* stmts);
Statement* ProcessStatement(Statement* stmt);
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
FlowGraph graph_;
ExitNode* global_exit_;
ZoneList<Node*> preorder_;
ZoneList<Node*> postorder_;
// The flow graph builder collects a list of explicit definitions
// (assignments and count operations) to stack-allocated variables to use
// for reaching definitions analysis. It does not count the implicit
// definition at function entry. AST node numbers in the AST are used to
// refer into this list.
int variable_count_;
ZoneList<Expression*> body_definitions_;
BasicBlock* entry_;
BasicBlock* exit_;
BasicBlock* current_;
DISALLOW_COPY_AND_ASSIGN(FlowGraphBuilder);
};
......
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