|
|
@ -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
|
|
|
|