Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "flow-graph.h" | 28 #include "flow-graph.h" |
| 29 #include "scopes.h" | |
| 29 | 30 |
| 30 namespace v8 { | 31 namespace v8 { |
| 31 namespace internal { | 32 namespace internal { |
| 32 | 33 |
| 33 void FlowGraph::AppendInstruction(AstNode* instruction) { | 34 void BasicBlock::BuildTraversalOrder(ZoneList<BasicBlock*>* preorder, |
| 34 // Add a (non-null) AstNode to the end of the graph fragment. | 35 ZoneList<BasicBlock*>* postorder, |
| 35 ASSERT(instruction != NULL); | 36 bool mark) { |
| 36 if (exit()->IsExitNode()) return; | 37 if (mark_ == mark) return; |
| 37 if (!exit()->IsBlockNode()) AppendNode(new BlockNode()); | 38 mark_ = mark; |
| 38 BlockNode::cast(exit())->AddInstruction(instruction); | 39 preorder->Add(this); |
| 39 } | 40 if (right_successor_ != NULL) { |
| 40 | 41 right_successor_->BuildTraversalOrder(preorder, postorder, mark); |
| 41 | |
| 42 void FlowGraph::AppendNode(Node* node) { | |
| 43 // Add a node to the end of the graph. An empty block is added to | |
| 44 // maintain edge-split form (that no join nodes or exit nodes as | |
| 45 // successors to branch nodes). | |
| 46 ASSERT(node != NULL); | |
| 47 if (exit()->IsExitNode()) return; | |
| 48 if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) { | |
| 49 AppendNode(new BlockNode()); | |
| 50 } | 42 } |
| 51 exit()->AddSuccessor(node); | 43 if (left_successor_ != NULL) { |
| 52 node->AddPredecessor(exit()); | 44 left_successor_->BuildTraversalOrder(preorder, postorder, mark); |
| 53 exit_ = node; | |
| 54 } | |
| 55 | |
| 56 | |
| 57 void FlowGraph::AppendGraph(FlowGraph* graph) { | |
| 58 // Add a flow graph fragment to the end of this one. An empty block is | |
| 59 // added to maintain edge-split form (that no join nodes or exit nodes as | |
| 60 // successors to branch nodes). | |
| 61 ASSERT(graph != NULL); | |
| 62 if (exit()->IsExitNode()) return; | |
| 63 Node* node = graph->entry(); | |
| 64 if (exit()->IsBranchNode() && (node->IsJoinNode() || node->IsExitNode())) { | |
| 65 AppendNode(new BlockNode()); | |
| 66 } | |
| 67 exit()->AddSuccessor(node); | |
| 68 node->AddPredecessor(exit()); | |
| 69 exit_ = graph->exit(); | |
| 70 } | |
| 71 | |
| 72 | |
| 73 void FlowGraph::Split(BranchNode* branch, | |
| 74 FlowGraph* left, | |
| 75 FlowGraph* right, | |
| 76 JoinNode* join) { | |
| 77 // Add the branch node, left flowgraph, join node. | |
| 78 AppendNode(branch); | |
| 79 AppendGraph(left); | |
| 80 AppendNode(join); | |
| 81 | |
| 82 // Splice in the right flowgraph. | |
| 83 right->AppendNode(join); | |
| 84 branch->AddSuccessor(right->entry()); | |
| 85 right->entry()->AddPredecessor(branch); | |
| 86 } | |
| 87 | |
| 88 | |
| 89 void FlowGraph::Loop(JoinNode* join, | |
| 90 FlowGraph* condition, | |
| 91 BranchNode* branch, | |
| 92 FlowGraph* body) { | |
| 93 // Add the join, condition and branch. Add join's predecessors in | |
| 94 // left-to-right order. | |
| 95 AppendNode(join); | |
| 96 body->AppendNode(join); | |
| 97 AppendGraph(condition); | |
| 98 AppendNode(branch); | |
| 99 | |
| 100 // Splice in the body flowgraph. | |
| 101 branch->AddSuccessor(body->entry()); | |
| 102 body->entry()->AddPredecessor(branch); | |
| 103 } | |
| 104 | |
| 105 | |
| 106 void ExitNode::Traverse(bool mark, | |
| 107 ZoneList<Node*>* preorder, | |
| 108 ZoneList<Node*>* postorder) { | |
| 109 preorder->Add(this); | |
| 110 postorder->Add(this); | |
| 111 } | |
| 112 | |
| 113 | |
| 114 void BlockNode::Traverse(bool mark, | |
| 115 ZoneList<Node*>* preorder, | |
| 116 ZoneList<Node*>* postorder) { | |
| 117 ASSERT(successor_ != NULL); | |
| 118 preorder->Add(this); | |
| 119 if (!successor_->IsMarkedWith(mark)) { | |
| 120 successor_->MarkWith(mark); | |
| 121 successor_->Traverse(mark, preorder, postorder); | |
| 122 } | 45 } |
| 123 postorder->Add(this); | 46 postorder->Add(this); |
| 124 } | 47 } |
| 125 | 48 |
| 126 | 49 |
| 127 void BranchNode::Traverse(bool mark, | 50 FlowGraph* FlowGraphBuilder::Build(FunctionLiteral* lit) { |
| 128 ZoneList<Node*>* preorder, | 51 // Create new entry and exit nodes. These will not change during |
| 129 ZoneList<Node*>* postorder) { | 52 // construction. |
| 130 ASSERT(successor0_ != NULL && successor1_ != NULL); | 53 entry_ = new BasicBlock(NULL); |
| 131 preorder->Add(this); | 54 exit_ = new BasicBlock(NULL); |
| 132 if (!successor1_->IsMarkedWith(mark)) { | 55 // Begin accumulating instructions in the entry block. |
| 133 successor1_->MarkWith(mark); | 56 current_ = entry_; |
| 134 successor1_->Traverse(mark, preorder, postorder); | 57 |
| 58 VisitDeclarations(lit->scope()->declarations()); | |
| 59 VisitStatements(lit->body()); | |
| 60 // In the event of stack overflow or failure to handle a syntactic | |
| 61 // construct, return an invalid flow graph. | |
| 62 if (HasStackOverflow()) return new FlowGraph(NULL, NULL); | |
| 63 | |
| 64 // If current is not the exit, add a link to the exit. | |
| 65 if (current_ != exit_) { | |
| 66 // If current already has a successor (i.e., will be a branch node) and | |
| 67 // if the exit already has a predecessor, insert an empty block to | |
| 68 // maintain edge split form. | |
| 69 if (current_->HasSuccessor() && exit_->HasPredecessor()) { | |
| 70 current_ = new BasicBlock(current_); | |
| 71 } | |
| 72 Literal* undefined = new Literal(Factory::undefined_value()); | |
| 73 current_->AddInstruction(new ReturnStatement(undefined)); | |
| 74 exit_->AddPredecessor(current_); | |
| 135 } | 75 } |
| 136 if (!successor0_->IsMarkedWith(mark)) { | 76 |
| 137 successor0_->MarkWith(mark); | 77 FlowGraph* graph = new FlowGraph(entry_, exit_); |
| 138 successor0_->Traverse(mark, preorder, postorder); | 78 bool mark = !entry_->GetMark(); |
| 79 entry_->BuildTraversalOrder(graph->preorder(), graph->postorder(), mark); | |
| 80 | |
| 81 #ifdef DEBUG | |
| 82 // Number the nodes in reverse postorder. | |
| 83 int n = 0; | |
| 84 for (int i = graph->postorder()->length() - 1; i >= 0; --i) { | |
| 85 graph->postorder()->at(i)->set_number(n++); | |
| 139 } | 86 } |
| 140 postorder->Add(this); | 87 #endif |
| 88 | |
| 89 return graph; | |
| 141 } | 90 } |
| 142 | 91 |
| 143 | 92 |
| 144 void JoinNode::Traverse(bool mark, | 93 void FlowGraphBuilder::VisitDeclaration(Declaration* decl) { |
| 145 ZoneList<Node*>* preorder, | 94 Variable* var = decl->proxy()->AsVariable(); |
| 146 ZoneList<Node*>* postorder) { | 95 Slot* slot = var->slot(); |
| 147 ASSERT(successor_ != NULL); | 96 // We allow only declarations that do not require code generation. |
| 148 preorder->Add(this); | 97 // The following all require code generation: global variables and |
| 149 if (!successor_->IsMarkedWith(mark)) { | 98 // functions, variables with slot type LOOKUP, declarations with |
| 150 successor_->MarkWith(mark); | 99 // mode CONST, and functions. |
| 151 successor_->Traverse(mark, preorder, postorder); | |
| 152 } | |
| 153 postorder->Add(this); | |
| 154 } | |
| 155 | 100 |
| 156 | 101 if (var->is_global() || |
| 157 void FlowGraphBuilder::Build(FunctionLiteral* lit) { | 102 (slot != NULL && slot->type() == Slot::LOOKUP) || |
| 158 global_exit_ = new ExitNode(); | 103 decl->mode() == Variable::CONST || |
| 159 VisitStatements(lit->body()); | 104 decl->fun() != NULL) { |
| 160 | 105 // Here and in the rest of the flow graph builder we indicate an |
| 161 if (HasStackOverflow()) return; | 106 // unsupported syntactic construct by setting the stack overflow |
| 162 | 107 // flag on the visitor. This causes bailout of the visitor. |
| 163 // The graph can end with a branch node (if the function ended with a | 108 SetStackOverflow(); |
| 164 // loop). Maintain edge-split form (no join nodes or exit nodes as | |
| 165 // successors to branch nodes). | |
| 166 if (graph_.exit()->IsBranchNode()) graph_.AppendNode(new BlockNode()); | |
| 167 graph_.AppendNode(global_exit_); | |
| 168 | |
| 169 // Build preorder and postorder traversal orders. All the nodes in | |
| 170 // the graph have the same mark flag. For the traversal, use that | |
| 171 // flag's negation. Traversal will flip all the flags. | |
| 172 bool mark = graph_.entry()->IsMarkedWith(false); | |
| 173 graph_.entry()->MarkWith(mark); | |
| 174 graph_.entry()->Traverse(mark, &preorder_, &postorder_); | |
| 175 } | |
| 176 | |
| 177 | |
| 178 // This function peels off one iteration of a for-loop. The return value | |
| 179 // is either a block statement containing the peeled loop or NULL in case | |
| 180 // there is a stack overflow. | |
| 181 static Statement* PeelForLoop(ForStatement* stmt) { | |
| 182 // Mark this for-statement as processed. | |
| 183 stmt->set_peel_this_loop(false); | |
| 184 | |
| 185 // Create new block containing the init statement of the for-loop and | |
| 186 // an if-statement containing the peeled iteration and the original | |
| 187 // loop without the init-statement. | |
| 188 Block* block = new Block(NULL, 2, false); | |
| 189 if (stmt->init() != NULL) { | |
| 190 Statement* init = stmt->init(); | |
| 191 // The init statement gets the statement position of the for-loop | |
| 192 // to make debugging of peeled loops possible. | |
| 193 init->set_statement_pos(stmt->statement_pos()); | |
| 194 block->AddStatement(init); | |
| 195 } | |
| 196 | |
| 197 // Copy the condition. | |
| 198 CopyAstVisitor copy_visitor; | |
| 199 Expression* cond_copy = stmt->cond() != NULL | |
| 200 ? copy_visitor.DeepCopyExpr(stmt->cond()) | |
| 201 : new Literal(Factory::true_value()); | |
| 202 if (copy_visitor.HasStackOverflow()) return NULL; | |
| 203 | |
| 204 // Construct a block with the peeled body and the rest of the for-loop. | |
| 205 Statement* body_copy = copy_visitor.DeepCopyStmt(stmt->body()); | |
| 206 if (copy_visitor.HasStackOverflow()) return NULL; | |
| 207 | |
| 208 Statement* next_copy = stmt->next() != NULL | |
| 209 ? copy_visitor.DeepCopyStmt(stmt->next()) | |
| 210 : new EmptyStatement(); | |
| 211 if (copy_visitor.HasStackOverflow()) return NULL; | |
| 212 | |
| 213 Block* peeled_body = new Block(NULL, 3, false); | |
| 214 peeled_body->AddStatement(body_copy); | |
| 215 peeled_body->AddStatement(next_copy); | |
| 216 peeled_body->AddStatement(stmt); | |
| 217 | |
| 218 // Remove the duplicated init statement from the for-statement. | |
| 219 stmt->set_init(NULL); | |
| 220 | |
| 221 // Create new test at the top and add it to the newly created block. | |
| 222 IfStatement* test = new IfStatement(cond_copy, | |
| 223 peeled_body, | |
| 224 new EmptyStatement()); | |
| 225 block->AddStatement(test); | |
| 226 return block; | |
| 227 } | |
| 228 | |
| 229 | |
| 230 void FlowGraphBuilder::VisitStatements(ZoneList<Statement*>* stmts) { | |
| 231 for (int i = 0, len = stmts->length(); i < len; i++) { | |
| 232 stmts->at(i) = ProcessStatement(stmts->at(i)); | |
| 233 } | 109 } |
| 234 } | 110 } |
| 235 | 111 |
| 236 | 112 |
| 237 Statement* FlowGraphBuilder::ProcessStatement(Statement* stmt) { | |
| 238 if (FLAG_loop_peeling && | |
| 239 stmt->AsForStatement() != NULL && | |
| 240 stmt->AsForStatement()->peel_this_loop()) { | |
| 241 Statement* tmp_stmt = PeelForLoop(stmt->AsForStatement()); | |
| 242 if (tmp_stmt == NULL) { | |
| 243 SetStackOverflow(); | |
| 244 } else { | |
| 245 stmt = tmp_stmt; | |
| 246 } | |
| 247 } | |
| 248 Visit(stmt); | |
| 249 return stmt; | |
| 250 } | |
| 251 | |
| 252 | |
| 253 void FlowGraphBuilder::VisitDeclaration(Declaration* decl) { | |
| 254 UNREACHABLE(); | |
| 255 } | |
| 256 | |
| 257 | |
| 258 void FlowGraphBuilder::VisitBlock(Block* stmt) { | 113 void FlowGraphBuilder::VisitBlock(Block* stmt) { |
| 259 VisitStatements(stmt->statements()); | 114 VisitStatements(stmt->statements()); |
| 260 } | 115 } |
| 261 | 116 |
| 262 | 117 |
| 263 void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { | 118 void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { |
| 264 Visit(stmt->expression()); | 119 Visit(stmt->expression()); |
| 265 } | 120 } |
| 266 | 121 |
| 267 | 122 |
| 268 void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { | 123 void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { |
| 269 // Nothing to do. | 124 // Nothing to do. |
| 270 } | 125 } |
| 271 | 126 |
| 272 | 127 |
| 273 void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) { | 128 void FlowGraphBuilder::VisitIfStatement(IfStatement* stmt) { |
| 129 // Build a diamond in the flow graph. First accumulate the instructions | |
| 130 // of the test in the current basic block. | |
| 274 Visit(stmt->condition()); | 131 Visit(stmt->condition()); |
| 275 | 132 |
| 276 BranchNode* branch = new BranchNode(); | 133 // Remember the branch node and accumulate the true branch as its left |
| 277 FlowGraph original = graph_; | 134 // successor. This relies on the successors being added left to right. |
| 278 graph_ = FlowGraph::Empty(); | 135 BasicBlock* branch = current_; |
| 279 stmt->set_then_statement(ProcessStatement(stmt->then_statement())); | 136 current_ = new BasicBlock(branch); |
| 137 Visit(stmt->then_statement()); | |
| 280 | 138 |
| 281 FlowGraph left = graph_; | 139 // Construct a join node and then accumulate the false branch in a fresh |
| 282 graph_ = FlowGraph::Empty(); | 140 // successor of the branch node. |
| 283 stmt->set_else_statement(ProcessStatement(stmt->else_statement())); | 141 BasicBlock* join = new BasicBlock(current_); |
| 142 current_ = new BasicBlock(branch); | |
| 143 Visit(stmt->else_statement()); | |
| 144 join->AddPredecessor(current_); | |
| 284 | 145 |
| 285 if (HasStackOverflow()) return; | 146 current_ = join; |
| 286 JoinNode* join = new JoinNode(); | |
| 287 original.Split(branch, &left, &graph_, join); | |
| 288 graph_ = original; | |
| 289 } | 147 } |
| 290 | 148 |
| 291 | 149 |
| 292 void FlowGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { | 150 void FlowGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { |
| 293 SetStackOverflow(); | 151 SetStackOverflow(); |
| 294 } | 152 } |
| 295 | 153 |
| 296 | 154 |
| 297 void FlowGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { | 155 void FlowGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { |
| 298 SetStackOverflow(); | 156 SetStackOverflow(); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 323 SetStackOverflow(); | 181 SetStackOverflow(); |
| 324 } | 182 } |
| 325 | 183 |
| 326 | 184 |
| 327 void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { | 185 void FlowGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { |
| 328 SetStackOverflow(); | 186 SetStackOverflow(); |
| 329 } | 187 } |
| 330 | 188 |
| 331 | 189 |
| 332 void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) { | 190 void FlowGraphBuilder::VisitForStatement(ForStatement* stmt) { |
| 333 if (stmt->init() != NULL) stmt->set_init(ProcessStatement(stmt->init())); | 191 // Build a loop in the flow graph. First accumulate the instructions of |
| 192 // the initializer in the current basic block. | |
| 193 if (stmt->init() != NULL) Visit(stmt->init()); | |
| 334 | 194 |
| 335 JoinNode* join = new JoinNode(); | 195 // Create a new basic block for the test. This will be the join node. |
| 336 FlowGraph original = graph_; | 196 BasicBlock* join = new BasicBlock(current_); |
| 337 graph_ = FlowGraph::Empty(); | 197 current_ = join; |
| 338 if (stmt->cond() != NULL) Visit(stmt->cond()); | 198 if (stmt->cond() != NULL) Visit(stmt->cond()); |
| 339 | 199 |
| 340 BranchNode* branch = new BranchNode(); | 200 // The current node is the branch node. Create a new basic block to begin |
| 341 FlowGraph condition = graph_; | 201 // the body. |
| 342 graph_ = FlowGraph::Empty(); | 202 BasicBlock* branch = current_; |
| 343 stmt->set_body(ProcessStatement(stmt->body())); | 203 current_ = new BasicBlock(branch); |
| 204 Visit(stmt->body()); | |
| 205 if (stmt->next() != NULL) Visit(stmt->next()); | |
| 344 | 206 |
| 345 if (stmt->next() != NULL) stmt->set_next(ProcessStatement(stmt->next())); | 207 // Add the backward edge from the end of the body and continue with the |
| 346 | 208 // false arm of the branch. |
| 347 if (HasStackOverflow()) return; | 209 join->AddPredecessor(current_); |
| 348 original.Loop(join, &condition, branch, &graph_); | 210 current_ = new BasicBlock(branch); |
| 349 graph_ = original; | |
| 350 } | 211 } |
| 351 | 212 |
| 352 | 213 |
| 353 void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) { | 214 void FlowGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
| 354 SetStackOverflow(); | 215 SetStackOverflow(); |
| 355 } | 216 } |
| 356 | 217 |
| 357 | 218 |
| 358 void FlowGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { | 219 void FlowGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { |
| 359 SetStackOverflow(); | 220 SetStackOverflow(); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 380 SetStackOverflow(); | 241 SetStackOverflow(); |
| 381 } | 242 } |
| 382 | 243 |
| 383 | 244 |
| 384 void FlowGraphBuilder::VisitConditional(Conditional* expr) { | 245 void FlowGraphBuilder::VisitConditional(Conditional* expr) { |
| 385 SetStackOverflow(); | 246 SetStackOverflow(); |
| 386 } | 247 } |
| 387 | 248 |
| 388 | 249 |
| 389 void FlowGraphBuilder::VisitSlot(Slot* expr) { | 250 void FlowGraphBuilder::VisitSlot(Slot* expr) { |
| 251 // Slots do not appear in the AST. | |
| 390 UNREACHABLE(); | 252 UNREACHABLE(); |
| 391 } | 253 } |
| 392 | 254 |
| 393 | 255 |
| 394 void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 256 void FlowGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 395 graph_.AppendInstruction(expr); | 257 current_->AddInstruction(expr); |
| 396 } | 258 } |
| 397 | 259 |
| 398 | 260 |
| 399 void FlowGraphBuilder::VisitLiteral(Literal* expr) { | 261 void FlowGraphBuilder::VisitLiteral(Literal* expr) { |
| 400 graph_.AppendInstruction(expr); | 262 current_->AddInstruction(expr); |
|
fschneider
2010/03/29 13:49:59
UNREACHABLE() here? Since literals are always triv
| |
| 401 } | 263 } |
| 402 | 264 |
| 403 | 265 |
| 404 void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { | 266 void FlowGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 405 SetStackOverflow(); | 267 SetStackOverflow(); |
| 406 } | 268 } |
| 407 | 269 |
| 408 | 270 |
| 409 void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { | 271 void FlowGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
| 410 SetStackOverflow(); | 272 SetStackOverflow(); |
| 411 } | 273 } |
| 412 | 274 |
| 413 | 275 |
| 414 void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { | 276 void FlowGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
| 415 SetStackOverflow(); | 277 SetStackOverflow(); |
| 416 } | 278 } |
| 417 | 279 |
| 418 | 280 |
| 419 void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | 281 void FlowGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
| 420 SetStackOverflow(); | 282 SetStackOverflow(); |
| 421 } | 283 } |
| 422 | 284 |
| 423 | 285 |
| 424 void FlowGraphBuilder::VisitAssignment(Assignment* expr) { | 286 void FlowGraphBuilder::VisitAssignment(Assignment* expr) { |
| 287 // There are three basic kinds of assignment: variable assignments, | |
| 288 // property assignments, and invalid left-hand sides (which are translated | |
| 289 // to "throw ReferenceError" by the parser). | |
| 425 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 290 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
| 426 Property* prop = expr->target()->AsProperty(); | 291 Property* prop = expr->target()->AsProperty(); |
| 427 // Left-hand side can be a variable or property (or reference error) but | |
| 428 // not both. | |
| 429 ASSERT(var == NULL || prop == NULL); | 292 ASSERT(var == NULL || prop == NULL); |
| 430 if (var != NULL) { | 293 if (var != NULL) { |
| 431 if (expr->is_compound()) Visit(expr->target()); | 294 if (expr->is_compound() && !expr->target()->IsTrivial()) { |
| 432 Visit(expr->value()); | 295 Visit(expr->target()); |
| 433 if (var->IsStackAllocated()) { | |
| 434 // The first definition in the body is numbered n, where n is the | |
| 435 // number of parameters and stack-allocated locals. | |
| 436 expr->set_num(body_definitions_.length() + variable_count_); | |
| 437 body_definitions_.Add(expr); | |
| 438 } | 296 } |
| 297 if (!expr->value()->IsTrivial()) Visit(expr->value()); | |
| 298 current_->AddInstruction(expr); | |
| 439 | 299 |
| 440 } else if (prop != NULL) { | 300 } else if (prop != NULL) { |
| 441 Visit(prop->obj()); | 301 if (!prop->obj()->IsTrivial()) Visit(prop->obj()); |
| 442 if (!prop->key()->IsPropertyName()) Visit(prop->key()); | 302 if (!prop->key()->IsPropertyName() && !prop->key()->IsTrivial()) { |
| 443 Visit(expr->value()); | 303 Visit(prop->key()); |
| 304 } | |
| 305 if (!expr->value()->IsTrivial()) Visit(expr->value()); | |
| 306 current_->AddInstruction(expr); | |
| 307 | |
| 308 } else { | |
| 309 Visit(expr->target()); | |
| 444 } | 310 } |
| 445 | |
| 446 if (HasStackOverflow()) return; | |
| 447 graph_.AppendInstruction(expr); | |
| 448 } | 311 } |
| 449 | 312 |
| 450 | 313 |
| 451 void FlowGraphBuilder::VisitThrow(Throw* expr) { | 314 void FlowGraphBuilder::VisitThrow(Throw* expr) { |
| 452 SetStackOverflow(); | 315 SetStackOverflow(); |
| 453 } | 316 } |
| 454 | 317 |
| 455 | 318 |
| 456 void FlowGraphBuilder::VisitProperty(Property* expr) { | 319 void FlowGraphBuilder::VisitProperty(Property* expr) { |
| 457 Visit(expr->obj()); | 320 if (!expr->obj()->IsTrivial()) Visit(expr->obj()); |
| 458 if (!expr->key()->IsPropertyName()) Visit(expr->key()); | 321 if (!expr->key()->IsPropertyName() && !expr->key()->IsTrivial()) { |
| 459 | 322 Visit(expr->key()); |
| 460 if (HasStackOverflow()) return; | 323 } |
| 461 graph_.AppendInstruction(expr); | 324 current_->AddInstruction(expr); |
| 462 } | 325 } |
| 463 | 326 |
| 464 | 327 |
| 465 void FlowGraphBuilder::VisitCall(Call* expr) { | 328 void FlowGraphBuilder::VisitCall(Call* expr) { |
| 466 Visit(expr->expression()); | 329 Visit(expr->expression()); |
| 467 ZoneList<Expression*>* arguments = expr->arguments(); | 330 VisitExpressions(expr->arguments()); |
| 468 for (int i = 0, len = arguments->length(); i < len; i++) { | 331 current_->AddInstruction(expr); |
| 469 Visit(arguments->at(i)); | |
| 470 } | |
| 471 | |
| 472 if (HasStackOverflow()) return; | |
| 473 graph_.AppendInstruction(expr); | |
| 474 } | 332 } |
| 475 | 333 |
| 476 | 334 |
| 477 void FlowGraphBuilder::VisitCallNew(CallNew* expr) { | 335 void FlowGraphBuilder::VisitCallNew(CallNew* expr) { |
| 478 SetStackOverflow(); | 336 SetStackOverflow(); |
| 479 } | 337 } |
| 480 | 338 |
| 481 | 339 |
| 482 void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) { | 340 void FlowGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
| 483 SetStackOverflow(); | 341 SetStackOverflow(); |
| 484 } | 342 } |
| 485 | 343 |
| 486 | 344 |
| 487 void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { | 345 void FlowGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 488 switch (expr->op()) { | 346 switch (expr->op()) { |
| 489 case Token::NOT: | 347 case Token::NOT: |
| 490 case Token::BIT_NOT: | 348 case Token::BIT_NOT: |
| 491 case Token::DELETE: | 349 case Token::DELETE: |
| 492 case Token::TYPEOF: | 350 case Token::TYPEOF: |
| 493 case Token::VOID: | 351 case Token::VOID: |
| 494 SetStackOverflow(); | 352 SetStackOverflow(); |
| 495 break; | 353 break; |
| 496 | 354 |
| 497 case Token::ADD: | 355 case Token::ADD: |
| 498 case Token::SUB: | 356 case Token::SUB: |
| 499 Visit(expr->expression()); | 357 Visit(expr->expression()); |
| 500 if (HasStackOverflow()) return; | 358 current_->AddInstruction(expr); |
| 501 graph_.AppendInstruction(expr); | |
| 502 break; | 359 break; |
| 503 | 360 |
| 504 default: | 361 default: |
| 505 UNREACHABLE(); | 362 UNREACHABLE(); |
| 506 } | 363 } |
| 507 } | 364 } |
| 508 | 365 |
| 509 | 366 |
| 510 void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) { | 367 void FlowGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| 511 Visit(expr->expression()); | 368 Visit(expr->expression()); |
| 512 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 369 current_->AddInstruction(expr); |
| 513 if (var != NULL && var->IsStackAllocated()) { | |
| 514 // The first definition in the body is numbered n, where n is the number | |
| 515 // of parameters and stack-allocated locals. | |
| 516 expr->set_num(body_definitions_.length() + variable_count_); | |
| 517 body_definitions_.Add(expr); | |
| 518 } | |
| 519 | |
| 520 if (HasStackOverflow()) return; | |
| 521 graph_.AppendInstruction(expr); | |
| 522 } | 370 } |
| 523 | 371 |
| 524 | 372 |
| 525 void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { | 373 void FlowGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
| 526 switch (expr->op()) { | 374 switch (expr->op()) { |
| 527 case Token::COMMA: | 375 case Token::COMMA: |
| 528 case Token::OR: | 376 case Token::OR: |
| 529 case Token::AND: | 377 case Token::AND: |
| 530 SetStackOverflow(); | 378 SetStackOverflow(); |
| 531 break; | 379 break; |
| 532 | 380 |
| 533 case Token::BIT_OR: | 381 case Token::BIT_OR: |
| 534 case Token::BIT_XOR: | 382 case Token::BIT_XOR: |
| 535 case Token::BIT_AND: | 383 case Token::BIT_AND: |
| 536 case Token::SHL: | 384 case Token::SHL: |
| 385 case Token::SAR: | |
| 537 case Token::SHR: | 386 case Token::SHR: |
| 538 case Token::ADD: | 387 case Token::ADD: |
| 539 case Token::SUB: | 388 case Token::SUB: |
| 540 case Token::MUL: | 389 case Token::MUL: |
| 541 case Token::DIV: | 390 case Token::DIV: |
| 542 case Token::MOD: | 391 case Token::MOD: |
| 543 case Token::SAR: | 392 if (!expr->left()->IsTrivial()) Visit(expr->left()); |
| 544 Visit(expr->left()); | 393 if (!expr->right()->IsTrivial()) Visit(expr->right()); |
| 545 Visit(expr->right()); | 394 current_->AddInstruction(expr); |
| 546 if (HasStackOverflow()) return; | |
| 547 graph_.AppendInstruction(expr); | |
| 548 break; | 395 break; |
| 549 | 396 |
| 550 default: | 397 default: |
| 551 UNREACHABLE(); | 398 UNREACHABLE(); |
| 552 } | 399 } |
| 553 } | 400 } |
| 554 | 401 |
| 555 | 402 |
| 556 void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) { | 403 void FlowGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| 557 switch (expr->op()) { | 404 switch (expr->op()) { |
| 558 case Token::EQ: | 405 case Token::EQ: |
| 559 case Token::NE: | 406 case Token::NE: |
| 560 case Token::EQ_STRICT: | 407 case Token::EQ_STRICT: |
| 561 case Token::NE_STRICT: | 408 case Token::NE_STRICT: |
| 562 case Token::INSTANCEOF: | 409 case Token::INSTANCEOF: |
| 563 case Token::IN: | 410 case Token::IN: |
| 564 SetStackOverflow(); | 411 SetStackOverflow(); |
| 565 break; | 412 break; |
| 566 | 413 |
| 567 case Token::LT: | 414 case Token::LT: |
| 568 case Token::GT: | 415 case Token::GT: |
| 569 case Token::LTE: | 416 case Token::LTE: |
| 570 case Token::GTE: | 417 case Token::GTE: |
| 571 Visit(expr->left()); | 418 if (!expr->left()->IsTrivial()) Visit(expr->left()); |
| 572 Visit(expr->right()); | 419 if (!expr->right()->IsTrivial()) Visit(expr->right()); |
| 573 if (HasStackOverflow()) return; | 420 current_->AddInstruction(expr); |
| 574 graph_.AppendInstruction(expr); | |
| 575 break; | 421 break; |
| 576 | 422 |
| 577 default: | 423 default: |
| 578 UNREACHABLE(); | 424 UNREACHABLE(); |
| 579 } | 425 } |
| 580 } | 426 } |
| 581 | 427 |
| 582 | 428 |
| 583 void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) { | 429 void FlowGraphBuilder::VisitThisFunction(ThisFunction* expr) { |
| 584 SetStackOverflow(); | 430 SetStackOverflow(); |
| 585 } | 431 } |
| 586 | 432 |
| 587 | 433 |
| 434 #ifdef DEBUG | |
| 435 | |
| 436 // Print a textual representation of an instruction in a flow graph. Using | |
| 437 // the AstVisitor is overkill because there is no recursion here. It is | |
| 438 // however only used for printing in debug mode. | |
| 439 class InstructionPrinter: public AstVisitor { | |
| 440 public: | |
| 441 InstructionPrinter() {} | |
| 442 | |
| 443 private: | |
| 444 // Overridden from the base class. | |
| 445 virtual void VisitExpressions(ZoneList<Expression*>* exprs); | |
| 446 | |
| 447 // AST node visit functions. | |
| 448 #define DECLARE_VISIT(type) virtual void Visit##type(type* node); | |
| 449 AST_NODE_LIST(DECLARE_VISIT) | |
| 450 #undef DECLARE_VISIT | |
| 451 | |
| 452 DISALLOW_COPY_AND_ASSIGN(InstructionPrinter); | |
| 453 }; | |
| 454 | |
| 455 | |
| 456 static void PrintSubexpression(Expression* expr) { | |
| 457 if (!expr->IsTrivial()) { | |
| 458 PrintF("@%d", expr->num()); | |
| 459 } else if (expr->AsLiteral() != NULL) { | |
| 460 expr->AsLiteral()->handle()->Print(); | |
| 461 } else if (expr->AsVariableProxy() != NULL) { | |
| 462 PrintF("%s", *expr->AsVariableProxy()->name()->ToCString()); | |
| 463 } else { | |
| 464 UNREACHABLE(); | |
| 465 } | |
| 466 } | |
| 467 | |
| 468 | |
| 469 void InstructionPrinter::VisitExpressions(ZoneList<Expression*>* exprs) { | |
| 470 for (int i = 0; i < exprs->length(); ++i) { | |
| 471 if (i != 0) PrintF(", "); | |
| 472 PrintF("@%d", exprs->at(i)->num()); | |
| 473 } | |
| 474 } | |
| 475 | |
| 476 | |
| 477 // We only define printing functions for the node types that can occur as | |
| 478 // instructions in a flow graph. The rest are unreachable. | |
| 479 void InstructionPrinter::VisitDeclaration(Declaration* decl) { | |
| 480 UNREACHABLE(); | |
| 481 } | |
| 482 | |
| 483 | |
| 484 void InstructionPrinter::VisitBlock(Block* stmt) { | |
| 485 UNREACHABLE(); | |
| 486 } | |
| 487 | |
| 488 | |
| 489 void InstructionPrinter::VisitExpressionStatement(ExpressionStatement* stmt) { | |
| 490 UNREACHABLE(); | |
| 491 } | |
| 492 | |
| 493 | |
| 494 void InstructionPrinter::VisitEmptyStatement(EmptyStatement* stmt) { | |
| 495 UNREACHABLE(); | |
| 496 } | |
| 497 | |
| 498 | |
| 499 void InstructionPrinter::VisitIfStatement(IfStatement* stmt) { | |
| 500 UNREACHABLE(); | |
| 501 } | |
| 502 | |
| 503 | |
| 504 void InstructionPrinter::VisitContinueStatement(ContinueStatement* stmt) { | |
| 505 UNREACHABLE(); | |
| 506 } | |
| 507 | |
| 508 | |
| 509 void InstructionPrinter::VisitBreakStatement(BreakStatement* stmt) { | |
| 510 UNREACHABLE(); | |
| 511 } | |
| 512 | |
| 513 | |
| 514 void InstructionPrinter::VisitReturnStatement(ReturnStatement* stmt) { | |
| 515 PrintF("return "); | |
| 516 PrintSubexpression(stmt->expression()); | |
| 517 } | |
| 518 | |
| 519 | |
| 520 void InstructionPrinter::VisitWithEnterStatement(WithEnterStatement* stmt) { | |
| 521 UNREACHABLE(); | |
| 522 } | |
| 523 | |
| 524 | |
| 525 void InstructionPrinter::VisitWithExitStatement(WithExitStatement* stmt) { | |
| 526 UNREACHABLE(); | |
| 527 } | |
| 528 | |
| 529 | |
| 530 void InstructionPrinter::VisitSwitchStatement(SwitchStatement* stmt) { | |
| 531 UNREACHABLE(); | |
| 532 } | |
| 533 | |
| 534 | |
| 535 void InstructionPrinter::VisitDoWhileStatement(DoWhileStatement* stmt) { | |
| 536 UNREACHABLE(); | |
| 537 } | |
| 538 | |
| 539 | |
| 540 void InstructionPrinter::VisitWhileStatement(WhileStatement* stmt) { | |
| 541 UNREACHABLE(); | |
| 542 } | |
| 543 | |
| 544 | |
| 545 void InstructionPrinter::VisitForStatement(ForStatement* stmt) { | |
| 546 UNREACHABLE(); | |
| 547 } | |
| 548 | |
| 549 | |
| 550 void InstructionPrinter::VisitForInStatement(ForInStatement* stmt) { | |
| 551 UNREACHABLE(); | |
| 552 } | |
| 553 | |
| 554 | |
| 555 void InstructionPrinter::VisitTryCatchStatement(TryCatchStatement* stmt) { | |
| 556 UNREACHABLE(); | |
| 557 } | |
| 558 | |
| 559 | |
| 560 void InstructionPrinter::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | |
| 561 UNREACHABLE(); | |
| 562 } | |
| 563 | |
| 564 | |
| 565 void InstructionPrinter::VisitDebuggerStatement(DebuggerStatement* stmt) { | |
| 566 UNREACHABLE(); | |
| 567 } | |
| 568 | |
| 569 | |
| 570 void InstructionPrinter::VisitFunctionLiteral(FunctionLiteral* expr) { | |
| 571 UNREACHABLE(); | |
| 572 } | |
| 573 | |
| 574 | |
| 575 void InstructionPrinter::VisitSharedFunctionInfoLiteral( | |
| 576 SharedFunctionInfoLiteral* expr) { | |
| 577 UNREACHABLE(); | |
| 578 } | |
| 579 | |
| 580 | |
| 581 void InstructionPrinter::VisitConditional(Conditional* expr) { | |
| 582 UNREACHABLE(); | |
| 583 } | |
| 584 | |
| 585 | |
| 586 void InstructionPrinter::VisitSlot(Slot* expr) { | |
| 587 UNREACHABLE(); | |
| 588 } | |
| 589 | |
| 590 | |
| 591 void InstructionPrinter::VisitVariableProxy(VariableProxy* expr) { | |
| 592 Variable* var = expr->AsVariable(); | |
| 593 if (var != NULL) { | |
| 594 PrintF("%s", *var->name()->ToCString()); | |
| 595 } else { | |
| 596 ASSERT(expr->AsProperty() != NULL); | |
| 597 VisitProperty(expr->AsProperty()); | |
| 598 } | |
| 599 } | |
| 600 | |
| 601 | |
| 602 void InstructionPrinter::VisitLiteral(Literal* expr) { | |
| 603 expr->handle()->Print(); | |
| 604 } | |
| 605 | |
| 606 | |
| 607 void InstructionPrinter::VisitRegExpLiteral(RegExpLiteral* expr) { | |
| 608 UNREACHABLE(); | |
| 609 } | |
| 610 | |
| 611 | |
| 612 void InstructionPrinter::VisitObjectLiteral(ObjectLiteral* expr) { | |
| 613 UNREACHABLE(); | |
| 614 } | |
| 615 | |
| 616 | |
| 617 void InstructionPrinter::VisitArrayLiteral(ArrayLiteral* expr) { | |
| 618 UNREACHABLE(); | |
| 619 } | |
| 620 | |
| 621 | |
| 622 void InstructionPrinter::VisitCatchExtensionObject( | |
| 623 CatchExtensionObject* expr) { | |
| 624 UNREACHABLE(); | |
| 625 } | |
| 626 | |
| 627 | |
| 628 void InstructionPrinter::VisitAssignment(Assignment* expr) { | |
| 629 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | |
| 630 Property* prop = expr->target()->AsProperty(); | |
| 631 | |
| 632 // Print the left-hand side. | |
| 633 Visit(expr->target()); | |
| 634 if (var == NULL && prop == NULL) return; // Throw reference error. | |
| 635 PrintF(" = "); | |
| 636 // For compound assignments, print the left-hand side again and the | |
| 637 // corresponding binary operator. | |
| 638 if (expr->is_compound()) { | |
| 639 PrintSubexpression(expr->target()); | |
| 640 PrintF(" %s ", Token::String(expr->binary_op())); | |
| 641 } | |
| 642 | |
| 643 // Print the right-hand side. | |
| 644 PrintSubexpression(expr->value()); | |
| 645 } | |
| 646 | |
| 647 | |
| 648 void InstructionPrinter::VisitThrow(Throw* expr) { | |
| 649 UNREACHABLE(); | |
| 650 } | |
| 651 | |
| 652 | |
| 653 void InstructionPrinter::VisitProperty(Property* expr) { | |
| 654 PrintSubexpression(expr->obj()); | |
| 655 if (expr->key()->IsPropertyName()) { | |
| 656 PrintF("."); | |
| 657 ASSERT(expr->key()->AsLiteral() != NULL); | |
| 658 expr->key()->AsLiteral()->handle()->Print(); | |
| 659 } else { | |
| 660 PrintF("["); | |
| 661 PrintSubexpression(expr->key()); | |
| 662 PrintF("]"); | |
| 663 } | |
| 664 } | |
| 665 | |
| 666 | |
| 667 void InstructionPrinter::VisitCall(Call* expr) { | |
| 668 PrintF("@%d(", expr->expression()->num()); | |
| 669 VisitExpressions(expr->arguments()); | |
| 670 PrintF(")"); | |
| 671 } | |
| 672 | |
| 673 | |
| 674 void InstructionPrinter::VisitCallNew(CallNew* expr) { | |
| 675 UNREACHABLE(); | |
| 676 } | |
| 677 | |
| 678 | |
| 679 void InstructionPrinter::VisitCallRuntime(CallRuntime* expr) { | |
| 680 UNREACHABLE(); | |
| 681 } | |
| 682 | |
| 683 | |
| 684 void InstructionPrinter::VisitUnaryOperation(UnaryOperation* expr) { | |
| 685 PrintF("%s(@%d)", Token::String(expr->op()), expr->expression()->num()); | |
| 686 } | |
| 687 | |
| 688 | |
| 689 void InstructionPrinter::VisitCountOperation(CountOperation* expr) { | |
| 690 if (expr->is_prefix()) { | |
| 691 PrintF("%s@%d", Token::String(expr->op()), expr->expression()->num()); | |
| 692 } else { | |
| 693 PrintF("@%d%s", expr->expression()->num(), Token::String(expr->op())); | |
| 694 } | |
| 695 } | |
| 696 | |
| 697 | |
| 698 void InstructionPrinter::VisitBinaryOperation(BinaryOperation* expr) { | |
| 699 PrintSubexpression(expr->left()); | |
| 700 PrintF(" %s ", Token::String(expr->op())); | |
| 701 PrintSubexpression(expr->right()); | |
| 702 } | |
| 703 | |
| 704 | |
| 705 void InstructionPrinter::VisitCompareOperation(CompareOperation* expr) { | |
| 706 PrintSubexpression(expr->left()); | |
| 707 PrintF(" %s ", Token::String(expr->op())); | |
| 708 PrintSubexpression(expr->right()); | |
| 709 } | |
| 710 | |
| 711 | |
| 712 void InstructionPrinter::VisitThisFunction(ThisFunction* expr) { | |
| 713 UNREACHABLE(); | |
| 714 } | |
| 715 | |
| 716 | |
| 717 int BasicBlock::PrintAsText(int instruction_number) { | |
| 718 // Print a label for all blocks except the entry. | |
| 719 if (HasPredecessor()) { | |
| 720 PrintF("L%d:", number()); | |
| 721 } | |
| 722 | |
| 723 // Number and print the instructions. Since AST child nodes are visited | |
| 724 // before their parents, the parent nodes can refer to them by number. | |
| 725 InstructionPrinter printer; | |
| 726 for (int i = 0; i < instructions_.length(); ++i) { | |
| 727 PrintF("\n%d ", instruction_number); | |
| 728 instructions_[i]->set_num(instruction_number++); | |
| 729 printer.Visit(instructions_[i]); | |
| 730 } | |
| 731 | |
| 732 // If this is the exit, print "exit". If there is a single successor, | |
| 733 // print "goto" successor on a separate line. If there are two | |
| 734 // successors, print "goto" successor on the same line as the last | |
| 735 // instruction in the block. There is a blank line between blocks (and | |
| 736 // after the last one). | |
| 737 if (left_successor_ == NULL) { | |
| 738 PrintF("\nexit\n\n"); | |
| 739 } else if (right_successor_ == NULL) { | |
| 740 PrintF("\ngoto L%d\n\n", left_successor_->number()); | |
| 741 } else { | |
| 742 PrintF(", goto (L%d, L%d)\n\n", | |
| 743 left_successor_->number(), | |
| 744 right_successor_->number()); | |
| 745 } | |
| 746 | |
| 747 return instruction_number; | |
| 748 } | |
| 749 | |
| 750 | |
| 751 void FlowGraph::PrintAsText(Handle<String> name) { | |
| 752 PrintF("\n==== name = \"%s\" ====\n", *name->ToCString()); | |
| 753 // Print nodes in reverse postorder. Note that AST node numbers are used | |
| 754 // during printing of instructions and thus their current values are | |
| 755 // destroyed. | |
| 756 int number = 0; | |
| 757 for (int i = postorder_.length() - 1; i >= 0; --i) { | |
| 758 number = postorder_[i]->PrintAsText(number); | |
| 759 } | |
| 760 } | |
| 761 | |
| 762 #endif // DEBUG | |
| 763 | |
| 764 | |
| 588 } } // namespace v8::internal | 765 } } // namespace v8::internal |
| OLD | NEW |