OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 |
(...skipping 24 matching lines...) Expand all Loading... |
35 namespace v8 { | 35 namespace v8 { |
36 namespace internal { | 36 namespace internal { |
37 | 37 |
38 | 38 |
39 CfgGlobals* CfgGlobals::top_ = NULL; | 39 CfgGlobals* CfgGlobals::top_ = NULL; |
40 | 40 |
41 | 41 |
42 CfgGlobals::CfgGlobals(FunctionLiteral* fun) | 42 CfgGlobals::CfgGlobals(FunctionLiteral* fun) |
43 : global_fun_(fun), | 43 : global_fun_(fun), |
44 global_exit_(new ExitNode()), | 44 global_exit_(new ExitNode()), |
| 45 effect_(new Effect()), |
45 #ifdef DEBUG | 46 #ifdef DEBUG |
46 node_counter_(0), | 47 node_counter_(0), |
| 48 temp_counter_(0), |
47 #endif | 49 #endif |
48 previous_(top_) { | 50 previous_(top_) { |
49 top_ = this; | 51 top_ = this; |
50 } | 52 } |
51 | 53 |
52 | 54 |
53 #define BAILOUT(reason) \ | 55 #define BAILOUT(reason) \ |
54 do { return NULL; } while (false) | 56 do { return NULL; } while (false) |
55 | 57 |
56 Cfg* Cfg::Build() { | 58 Cfg* Cfg::Build() { |
57 FunctionLiteral* fun = CfgGlobals::current()->fun(); | 59 FunctionLiteral* fun = CfgGlobals::current()->fun(); |
58 if (fun->scope()->num_heap_slots() > 0) { | 60 if (fun->scope()->num_heap_slots() > 0) { |
59 BAILOUT("function has context slots"); | 61 BAILOUT("function has context slots"); |
60 } | 62 } |
61 if (fun->scope()->arguments() != NULL) { | 63 if (fun->scope()->arguments() != NULL) { |
62 BAILOUT("function uses .arguments"); | 64 BAILOUT("function uses .arguments"); |
63 } | 65 } |
64 | 66 |
65 ZoneList<Statement*>* body = fun->body(); | 67 ZoneList<Statement*>* body = fun->body(); |
66 if (body->is_empty()) { | 68 if (body->is_empty()) { |
67 BAILOUT("empty function body"); | 69 BAILOUT("empty function body"); |
68 } | 70 } |
69 | 71 |
70 StatementBuilder builder; | 72 StatementBuilder builder; |
71 builder.VisitStatements(body); | 73 builder.VisitStatements(body); |
72 Cfg* cfg = builder.cfg(); | 74 Cfg* cfg = builder.cfg(); |
73 if (cfg == NULL) { | 75 if (cfg == NULL) { |
74 BAILOUT("unsupported statement type"); | 76 BAILOUT("unsupported statement type"); |
75 } | 77 } |
| 78 if (cfg->is_empty()) { |
| 79 BAILOUT("function body produces empty cfg"); |
| 80 } |
76 if (cfg->has_exit()) { | 81 if (cfg->has_exit()) { |
77 BAILOUT("control path without explicit return"); | 82 BAILOUT("control path without explicit return"); |
78 } | 83 } |
79 cfg->PrependEntryNode(); | 84 cfg->PrependEntryNode(); |
80 return cfg; | 85 return cfg; |
81 } | 86 } |
82 | 87 |
83 #undef BAILOUT | 88 #undef BAILOUT |
84 | 89 |
85 | 90 |
86 void Cfg::PrependEntryNode() { | 91 void Cfg::PrependEntryNode() { |
87 ASSERT(!is_empty()); | 92 ASSERT(!is_empty()); |
88 entry_ = new EntryNode(InstructionBlock::cast(entry())); | 93 entry_ = new EntryNode(InstructionBlock::cast(entry())); |
89 } | 94 } |
90 | 95 |
91 | 96 |
92 void Cfg::Append(Instruction* instr) { | 97 void Cfg::Append(Instruction* instr) { |
93 ASSERT(has_exit()); | 98 ASSERT(is_empty() || has_exit()); |
94 ASSERT(!is_empty()); | 99 if (is_empty()) { |
| 100 entry_ = exit_ = new InstructionBlock(); |
| 101 } |
95 InstructionBlock::cast(exit_)->Append(instr); | 102 InstructionBlock::cast(exit_)->Append(instr); |
96 } | 103 } |
97 | 104 |
98 | 105 |
99 void Cfg::AppendReturnInstruction(Value* value) { | 106 void Cfg::AppendReturnInstruction(Value* value) { |
100 Append(new ReturnInstr(value)); | 107 Append(new ReturnInstr(value)); |
101 ExitNode* global_exit = CfgGlobals::current()->exit(); | 108 ExitNode* global_exit = CfgGlobals::current()->exit(); |
102 InstructionBlock::cast(exit_)->set_successor(global_exit); | 109 InstructionBlock::cast(exit_)->set_successor(global_exit); |
103 exit_ = NULL; | 110 exit_ = NULL; |
104 } | 111 } |
105 | 112 |
106 | 113 |
| 114 void Cfg::Concatenate(Cfg* other) { |
| 115 ASSERT(is_empty() || has_exit()); |
| 116 if (other->is_empty()) return; |
| 117 |
| 118 if (is_empty()) { |
| 119 entry_ = other->entry(); |
| 120 exit_ = other->exit(); |
| 121 } else { |
| 122 // We have a pair of nonempty fragments and this has an available exit. |
| 123 // Destructively glue the fragments together. |
| 124 InstructionBlock* first = InstructionBlock::cast(exit_); |
| 125 InstructionBlock* second = InstructionBlock::cast(other->entry()); |
| 126 first->instructions()->AddAll(*second->instructions()); |
| 127 if (second->successor() != NULL) { |
| 128 first->set_successor(second->successor()); |
| 129 exit_ = other->exit(); |
| 130 } |
| 131 } |
| 132 } |
| 133 |
| 134 |
107 void InstructionBlock::Unmark() { | 135 void InstructionBlock::Unmark() { |
108 if (is_marked_) { | 136 if (is_marked_) { |
109 is_marked_ = false; | 137 is_marked_ = false; |
110 successor_->Unmark(); | 138 successor_->Unmark(); |
111 } | 139 } |
112 } | 140 } |
113 | 141 |
114 | 142 |
115 void EntryNode::Unmark() { | 143 void EntryNode::Unmark() { |
116 if (is_marked_) { | 144 if (is_marked_) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 } | 187 } |
160 PrintF("--- Code ---\n"); | 188 PrintF("--- Code ---\n"); |
161 code->Disassemble(*fun->name()->ToCString()); | 189 code->Disassemble(*fun->name()->ToCString()); |
162 } | 190 } |
163 #endif | 191 #endif |
164 | 192 |
165 return code; | 193 return code; |
166 } | 194 } |
167 | 195 |
168 | 196 |
| 197 void BinaryOpInstr::FastAllocate(TempLocation* temp) { |
| 198 ASSERT(temp->where() == TempLocation::NOWHERE); |
| 199 if (temp == val0_ || temp == val1_) { |
| 200 temp->set_where(TempLocation::ACCUMULATOR); |
| 201 } else { |
| 202 temp->set_where(TempLocation::STACK); |
| 203 } |
| 204 } |
| 205 |
| 206 |
| 207 void ReturnInstr::FastAllocate(TempLocation* temp) { |
| 208 ASSERT(temp->where() == TempLocation::NOWHERE); |
| 209 if (temp == value_) { |
| 210 temp->set_where(TempLocation::ACCUMULATOR); |
| 211 } else { |
| 212 temp->set_where(TempLocation::STACK); |
| 213 } |
| 214 } |
| 215 |
| 216 |
169 // The expression builder should not be used for declarations or statements. | 217 // The expression builder should not be used for declarations or statements. |
170 void ExpressionBuilder::VisitDeclaration(Declaration* decl) { UNREACHABLE(); } | 218 void ExpressionBuilder::VisitDeclaration(Declaration* decl) { UNREACHABLE(); } |
171 | 219 |
172 #define DEFINE_VISIT(type) \ | 220 #define DEFINE_VISIT(type) \ |
173 void ExpressionBuilder::Visit##type(type* stmt) { UNREACHABLE(); } | 221 void ExpressionBuilder::Visit##type(type* stmt) { UNREACHABLE(); } |
174 STATEMENT_NODE_LIST(DEFINE_VISIT) | 222 STATEMENT_NODE_LIST(DEFINE_VISIT) |
175 #undef DEFINE_VISIT | 223 #undef DEFINE_VISIT |
176 | 224 |
177 | 225 |
178 // Macros (temporarily) handling unsupported expression types. | 226 // Macros (temporarily) handling unsupported expression types. |
179 #define BAILOUT(reason) \ | 227 #define BAILOUT(reason) \ |
180 do { \ | 228 do { \ |
181 value_ = NULL; \ | 229 cfg_ = NULL; \ |
182 return; \ | 230 return; \ |
183 } while (false) | 231 } while (false) |
184 | 232 |
185 #define CHECK_BAILOUT() \ | |
186 if (value_ == NULL) { return; } else {} | |
187 | |
188 void ExpressionBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { | 233 void ExpressionBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { |
189 BAILOUT("FunctionLiteral"); | 234 BAILOUT("FunctionLiteral"); |
190 } | 235 } |
191 | 236 |
192 | 237 |
193 void ExpressionBuilder::VisitFunctionBoilerplateLiteral( | 238 void ExpressionBuilder::VisitFunctionBoilerplateLiteral( |
194 FunctionBoilerplateLiteral* expr) { | 239 FunctionBoilerplateLiteral* expr) { |
195 BAILOUT("FunctionBoilerplateLiteral"); | 240 BAILOUT("FunctionBoilerplateLiteral"); |
196 } | 241 } |
197 | 242 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 BAILOUT("UnaryOperation"); | 328 BAILOUT("UnaryOperation"); |
284 } | 329 } |
285 | 330 |
286 | 331 |
287 void ExpressionBuilder::VisitCountOperation(CountOperation* expr) { | 332 void ExpressionBuilder::VisitCountOperation(CountOperation* expr) { |
288 BAILOUT("CountOperation"); | 333 BAILOUT("CountOperation"); |
289 } | 334 } |
290 | 335 |
291 | 336 |
292 void ExpressionBuilder::VisitBinaryOperation(BinaryOperation* expr) { | 337 void ExpressionBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
293 BAILOUT("BinaryOperation"); | 338 Token::Value op = expr->op(); |
| 339 switch (op) { |
| 340 case Token::COMMA: |
| 341 case Token::OR: |
| 342 case Token::AND: |
| 343 BAILOUT("unsupported binary operation"); |
| 344 |
| 345 case Token::BIT_OR: |
| 346 case Token::BIT_XOR: |
| 347 case Token::BIT_AND: |
| 348 case Token::SHL: |
| 349 case Token::SAR: |
| 350 case Token::SHR: |
| 351 case Token::ADD: |
| 352 case Token::SUB: |
| 353 case Token::MUL: |
| 354 case Token::DIV: |
| 355 case Token::MOD: { |
| 356 ExpressionBuilder left, right; |
| 357 left.Build(expr->left()); |
| 358 if (left.cfg() == NULL) { |
| 359 BAILOUT("unsupported left subexpression in binop"); |
| 360 } |
| 361 right.Build(expr->right()); |
| 362 if (right.cfg() == NULL) { |
| 363 BAILOUT("unsupported right subexpression in binop"); |
| 364 } |
| 365 |
| 366 Location* temp = new TempLocation(); |
| 367 cfg_ = left.cfg(); |
| 368 cfg_->Concatenate(right.cfg()); |
| 369 cfg_->Append(new BinaryOpInstr(temp, op, left.value(), right.value())); |
| 370 |
| 371 value_ = temp; |
| 372 return; |
| 373 } |
| 374 |
| 375 default: |
| 376 UNREACHABLE(); |
| 377 } |
294 } | 378 } |
295 | 379 |
296 | 380 |
297 void ExpressionBuilder::VisitCompareOperation(CompareOperation* expr) { | 381 void ExpressionBuilder::VisitCompareOperation(CompareOperation* expr) { |
298 BAILOUT("CompareOperation"); | 382 BAILOUT("CompareOperation"); |
299 } | 383 } |
300 | 384 |
301 | 385 |
302 void ExpressionBuilder::VisitThisFunction(ThisFunction* expr) { | 386 void ExpressionBuilder::VisitThisFunction(ThisFunction* expr) { |
303 BAILOUT("ThisFunction"); | 387 BAILOUT("ThisFunction"); |
304 } | 388 } |
305 | 389 |
306 #undef BAILOUT | 390 #undef BAILOUT |
307 #undef CHECK_BAILOUT | |
308 | 391 |
309 | 392 |
310 // Macros (temporarily) handling unsupported statement types. | 393 // Macros (temporarily) handling unsupported statement types. |
311 #define BAILOUT(reason) \ | 394 #define BAILOUT(reason) \ |
312 do { \ | 395 do { \ |
313 cfg_ = NULL; \ | 396 cfg_ = NULL; \ |
314 return; \ | 397 return; \ |
315 } while (false) | 398 } while (false) |
316 | 399 |
317 #define CHECK_BAILOUT() \ | 400 #define CHECK_BAILOUT() \ |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 } | 443 } |
361 | 444 |
362 | 445 |
363 void StatementBuilder::VisitBreakStatement(BreakStatement* stmt) { | 446 void StatementBuilder::VisitBreakStatement(BreakStatement* stmt) { |
364 BAILOUT("BreakStatement"); | 447 BAILOUT("BreakStatement"); |
365 } | 448 } |
366 | 449 |
367 | 450 |
368 void StatementBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 451 void StatementBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
369 ExpressionBuilder builder; | 452 ExpressionBuilder builder; |
370 builder.Visit(stmt->expression()); | 453 builder.Build(stmt->expression()); |
371 Value* value = builder.value(); | 454 if (builder.cfg() == NULL) { |
372 if (value == NULL) BAILOUT("unsupported expression type"); | 455 BAILOUT("unsupported expression in return statement"); |
373 cfg_->AppendReturnInstruction(value); | 456 } |
| 457 |
| 458 cfg_->Concatenate(builder.cfg()); |
| 459 cfg_->AppendReturnInstruction(builder.value()); |
374 } | 460 } |
375 | 461 |
376 | 462 |
377 void StatementBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { | 463 void StatementBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { |
378 BAILOUT("WithEnterStatement"); | 464 BAILOUT("WithEnterStatement"); |
379 } | 465 } |
380 | 466 |
381 | 467 |
382 void StatementBuilder::VisitWithExitStatement(WithExitStatement* stmt) { | 468 void StatementBuilder::VisitWithExitStatement(WithExitStatement* stmt) { |
383 BAILOUT("WithExitStatement"); | 469 BAILOUT("WithExitStatement"); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 } | 509 } |
424 | 510 |
425 | 511 |
426 void Constant::Print() { | 512 void Constant::Print() { |
427 PrintF("Constant("); | 513 PrintF("Constant("); |
428 handle_->Print(); | 514 handle_->Print(); |
429 PrintF(")"); | 515 PrintF(")"); |
430 } | 516 } |
431 | 517 |
432 | 518 |
| 519 void Effect::Print() { |
| 520 PrintF("Effect"); |
| 521 } |
| 522 |
| 523 |
433 void SlotLocation::Print() { | 524 void SlotLocation::Print() { |
434 PrintF("Slot("); | 525 PrintF("Slot("); |
435 switch (type_) { | 526 switch (type_) { |
436 case Slot::PARAMETER: | 527 case Slot::PARAMETER: |
437 PrintF("PARAMETER, %d)", index_); | 528 PrintF("PARAMETER, %d)", index_); |
438 break; | 529 break; |
439 case Slot::LOCAL: | 530 case Slot::LOCAL: |
440 PrintF("LOCAL, %d)", index_); | 531 PrintF("LOCAL, %d)", index_); |
441 break; | 532 break; |
442 default: | 533 default: |
443 UNREACHABLE(); | 534 UNREACHABLE(); |
444 } | 535 } |
445 } | 536 } |
446 | 537 |
447 | 538 |
| 539 void TempLocation::Print() { |
| 540 PrintF("Temp(%d)", number()); |
| 541 } |
| 542 |
| 543 |
| 544 void BinaryOpInstr::Print() { |
| 545 PrintF("BinaryOp("); |
| 546 loc_->Print(); |
| 547 PrintF(", %s, ", Token::Name(op_)); |
| 548 val0_->Print(); |
| 549 PrintF(", "); |
| 550 val1_->Print(); |
| 551 PrintF(")\n"); |
| 552 } |
| 553 |
| 554 |
448 void ReturnInstr::Print() { | 555 void ReturnInstr::Print() { |
449 PrintF("Return "); | 556 PrintF("Return("); |
450 value_->Print(); | 557 value_->Print(); |
451 PrintF("\n"); | 558 PrintF(")\n"); |
452 } | 559 } |
453 | 560 |
454 | 561 |
455 void InstructionBlock::Print() { | 562 void InstructionBlock::Print() { |
456 if (!is_marked_) { | 563 if (!is_marked_) { |
457 is_marked_ = true; | 564 is_marked_ = true; |
458 PrintF("L%d:\n", number()); | 565 PrintF("L%d:\n", number()); |
459 for (int i = 0, len = instructions_.length(); i < len; i++) { | 566 for (int i = 0, len = instructions_.length(); i < len; i++) { |
460 instructions_[i]->Print(); | 567 instructions_[i]->Print(); |
461 } | 568 } |
(...skipping 14 matching lines...) Expand all Loading... |
476 void ExitNode::Print() { | 583 void ExitNode::Print() { |
477 if (!is_marked_) { | 584 if (!is_marked_) { |
478 is_marked_ = true; | 585 is_marked_ = true; |
479 PrintF("L%d:\nExit\n\n", number()); | 586 PrintF("L%d:\nExit\n\n", number()); |
480 } | 587 } |
481 } | 588 } |
482 | 589 |
483 #endif // DEBUG | 590 #endif // DEBUG |
484 | 591 |
485 } } // namespace v8::internal | 592 } } // namespace v8::internal |
OLD | NEW |