}
-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.
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;
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> {};
};
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()); }
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; }
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_; }
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_; }
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_; }
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.
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_; }
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_; }
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; }
}
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
}
}
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
}
// 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_; }
#include "v8.h"
#include "data-flow.h"
-#include "flow-graph.h"
#include "scopes.h"
namespace v8 {
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);
}
}
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());
}
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());
}
}
-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
};
-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
// 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();
+ }
}
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;
}
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);
}
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);
}
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());
+ }
}
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);
}
case Token::ADD:
case Token::SUB:
Visit(expr->expression());
- if (HasStackOverflow()) return;
- graph_.AppendInstruction(expr);
+ current_->AddInstruction(expr);
break;
default:
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);
}
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:
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:
}
+#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
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);
};