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