| OLD | NEW |
| (Empty) |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | |
| 2 // Redistribution and use in source and binary forms, with or without | |
| 3 // modification, are permitted provided that the following conditions are | |
| 4 // met: | |
| 5 // | |
| 6 // * Redistributions of source code must retain the above copyright | |
| 7 // notice, this list of conditions and the following disclaimer. | |
| 8 // * Redistributions in binary form must reproduce the above | |
| 9 // copyright notice, this list of conditions and the following | |
| 10 // disclaimer in the documentation and/or other materials provided | |
| 11 // with the distribution. | |
| 12 // * Neither the name of Google Inc. nor the names of its | |
| 13 // contributors may be used to endorse or promote products derived | |
| 14 // from this software without specific prior written permission. | |
| 15 // | |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 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. | |
| 27 | |
| 28 #include "v8.h" | |
| 29 | |
| 30 #include "bootstrapper.h" | |
| 31 #include "cfg.h" | |
| 32 #include "scopeinfo.h" | |
| 33 #include "scopes.h" | |
| 34 | |
| 35 namespace v8 { | |
| 36 namespace internal { | |
| 37 | |
| 38 | |
| 39 CfgGlobals* CfgGlobals::top_ = NULL; | |
| 40 | |
| 41 | |
| 42 CfgGlobals::CfgGlobals(FunctionLiteral* fun) | |
| 43 : global_fun_(fun), | |
| 44 global_exit_(new ExitNode()), | |
| 45 nowhere_(new Nowhere()), | |
| 46 #ifdef DEBUG | |
| 47 node_counter_(0), | |
| 48 temp_counter_(0), | |
| 49 #endif | |
| 50 previous_(top_) { | |
| 51 top_ = this; | |
| 52 } | |
| 53 | |
| 54 | |
| 55 #define BAILOUT(reason) \ | |
| 56 do { return NULL; } while (false) | |
| 57 | |
| 58 Cfg* Cfg::Build() { | |
| 59 FunctionLiteral* fun = CfgGlobals::current()->fun(); | |
| 60 if (fun->scope()->num_heap_slots() > 0) { | |
| 61 BAILOUT("function has context slots"); | |
| 62 } | |
| 63 if (fun->scope()->num_stack_slots() > kBitsPerPointer) { | |
| 64 BAILOUT("function has too many locals"); | |
| 65 } | |
| 66 if (fun->scope()->num_parameters() > kBitsPerPointer - 1) { | |
| 67 BAILOUT("function has too many parameters"); | |
| 68 } | |
| 69 if (fun->scope()->arguments() != NULL) { | |
| 70 BAILOUT("function uses .arguments"); | |
| 71 } | |
| 72 | |
| 73 ZoneList<Statement*>* body = fun->body(); | |
| 74 if (body->is_empty()) { | |
| 75 BAILOUT("empty function body"); | |
| 76 } | |
| 77 | |
| 78 StatementCfgBuilder builder; | |
| 79 builder.VisitStatements(body); | |
| 80 Cfg* graph = builder.graph(); | |
| 81 if (graph == NULL) { | |
| 82 BAILOUT("unsupported statement type"); | |
| 83 } | |
| 84 if (graph->is_empty()) { | |
| 85 BAILOUT("function body produces empty cfg"); | |
| 86 } | |
| 87 if (graph->has_exit()) { | |
| 88 BAILOUT("control path without explicit return"); | |
| 89 } | |
| 90 graph->PrependEntryNode(); | |
| 91 return graph; | |
| 92 } | |
| 93 | |
| 94 #undef BAILOUT | |
| 95 | |
| 96 | |
| 97 void Cfg::PrependEntryNode() { | |
| 98 ASSERT(!is_empty()); | |
| 99 entry_ = new EntryNode(InstructionBlock::cast(entry())); | |
| 100 } | |
| 101 | |
| 102 | |
| 103 void Cfg::Append(Instruction* instr) { | |
| 104 ASSERT(is_empty() || has_exit()); | |
| 105 if (is_empty()) { | |
| 106 entry_ = exit_ = new InstructionBlock(); | |
| 107 } | |
| 108 InstructionBlock::cast(exit_)->Append(instr); | |
| 109 } | |
| 110 | |
| 111 | |
| 112 void Cfg::AppendReturnInstruction(Value* value) { | |
| 113 Append(new ReturnInstr(value)); | |
| 114 ExitNode* global_exit = CfgGlobals::current()->exit(); | |
| 115 InstructionBlock::cast(exit_)->set_successor(global_exit); | |
| 116 exit_ = NULL; | |
| 117 } | |
| 118 | |
| 119 | |
| 120 void Cfg::Concatenate(Cfg* other) { | |
| 121 ASSERT(is_empty() || has_exit()); | |
| 122 if (other->is_empty()) return; | |
| 123 | |
| 124 if (is_empty()) { | |
| 125 entry_ = other->entry(); | |
| 126 exit_ = other->exit(); | |
| 127 } else { | |
| 128 // We have a pair of nonempty fragments and this has an available exit. | |
| 129 // Destructively glue the fragments together. | |
| 130 InstructionBlock* first = InstructionBlock::cast(exit_); | |
| 131 InstructionBlock* second = InstructionBlock::cast(other->entry()); | |
| 132 first->instructions()->AddAll(*second->instructions()); | |
| 133 if (second->successor() != NULL) { | |
| 134 first->set_successor(second->successor()); | |
| 135 exit_ = other->exit(); | |
| 136 } | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 | |
| 141 void InstructionBlock::Unmark() { | |
| 142 if (is_marked_) { | |
| 143 is_marked_ = false; | |
| 144 successor_->Unmark(); | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 | |
| 149 void EntryNode::Unmark() { | |
| 150 if (is_marked_) { | |
| 151 is_marked_ = false; | |
| 152 successor_->Unmark(); | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 | |
| 157 void ExitNode::Unmark() { | |
| 158 is_marked_ = false; | |
| 159 } | |
| 160 | |
| 161 | |
| 162 Handle<Code> Cfg::Compile(Handle<Script> script) { | |
| 163 const int kInitialBufferSize = 4 * KB; | |
| 164 MacroAssembler* masm = new MacroAssembler(NULL, kInitialBufferSize); | |
| 165 entry()->Compile(masm); | |
| 166 entry()->Unmark(); | |
| 167 CodeDesc desc; | |
| 168 masm->GetCode(&desc); | |
| 169 FunctionLiteral* fun = CfgGlobals::current()->fun(); | |
| 170 ZoneScopeInfo info(fun->scope()); | |
| 171 InLoopFlag in_loop = fun->loop_nesting() ? IN_LOOP : NOT_IN_LOOP; | |
| 172 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop); | |
| 173 Handle<Code> code = Factory::NewCode(desc, &info, flags, masm->CodeObject()); | |
| 174 | |
| 175 // Add unresolved entries in the code to the fixup list. | |
| 176 Bootstrapper::AddFixup(*code, masm); | |
| 177 | |
| 178 #ifdef ENABLE_DISASSEMBLER | |
| 179 if (FLAG_print_code) { | |
| 180 // Print the source code if available. | |
| 181 if (!script->IsUndefined() && !script->source()->IsUndefined()) { | |
| 182 PrintF("--- Raw source ---\n"); | |
| 183 StringInputBuffer stream(String::cast(script->source())); | |
| 184 stream.Seek(fun->start_position()); | |
| 185 // fun->end_position() points to the last character in the | |
| 186 // stream. We need to compensate by adding one to calculate the | |
| 187 // length. | |
| 188 int source_len = fun->end_position() - fun->start_position() + 1; | |
| 189 for (int i = 0; i < source_len; i++) { | |
| 190 if (stream.has_more()) PrintF("%c", stream.GetNext()); | |
| 191 } | |
| 192 PrintF("\n\n"); | |
| 193 } | |
| 194 PrintF("--- Code ---\n"); | |
| 195 code->Disassemble(*fun->name()->ToCString()); | |
| 196 } | |
| 197 #endif | |
| 198 | |
| 199 return code; | |
| 200 } | |
| 201 | |
| 202 | |
| 203 void ZeroOperandInstruction::FastAllocate(TempLocation* temp) { | |
| 204 temp->set_where(TempLocation::STACK); | |
| 205 } | |
| 206 | |
| 207 | |
| 208 void OneOperandInstruction::FastAllocate(TempLocation* temp) { | |
| 209 temp->set_where((temp == value_) | |
| 210 ? TempLocation::ACCUMULATOR | |
| 211 : TempLocation::STACK); | |
| 212 } | |
| 213 | |
| 214 | |
| 215 void TwoOperandInstruction::FastAllocate(TempLocation* temp) { | |
| 216 temp->set_where((temp == value0_ || temp == value1_) | |
| 217 ? TempLocation::ACCUMULATOR | |
| 218 : TempLocation::STACK); | |
| 219 } | |
| 220 | |
| 221 | |
| 222 void PositionInstr::Compile(MacroAssembler* masm) { | |
| 223 if (FLAG_debug_info && pos_ != RelocInfo::kNoPosition) { | |
| 224 masm->RecordStatementPosition(pos_); | |
| 225 masm->RecordPosition(pos_); | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 | |
| 230 void MoveInstr::Compile(MacroAssembler* masm) { | |
| 231 location()->Move(masm, value()); | |
| 232 } | |
| 233 | |
| 234 | |
| 235 // The expression builder should not be used for declarations or statements. | |
| 236 void ExpressionCfgBuilder::VisitDeclaration(Declaration* decl) { | |
| 237 UNREACHABLE(); | |
| 238 } | |
| 239 | |
| 240 #define DEFINE_VISIT(type) \ | |
| 241 void ExpressionCfgBuilder::Visit##type(type* stmt) { UNREACHABLE(); } | |
| 242 STATEMENT_NODE_LIST(DEFINE_VISIT) | |
| 243 #undef DEFINE_VISIT | |
| 244 | |
| 245 | |
| 246 // Macros (temporarily) handling unsupported expression types. | |
| 247 #define BAILOUT(reason) \ | |
| 248 do { \ | |
| 249 graph_ = NULL; \ | |
| 250 return; \ | |
| 251 } while (false) | |
| 252 | |
| 253 void ExpressionCfgBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { | |
| 254 BAILOUT("FunctionLiteral"); | |
| 255 } | |
| 256 | |
| 257 | |
| 258 void ExpressionCfgBuilder::VisitFunctionBoilerplateLiteral( | |
| 259 FunctionBoilerplateLiteral* expr) { | |
| 260 BAILOUT("FunctionBoilerplateLiteral"); | |
| 261 } | |
| 262 | |
| 263 | |
| 264 void ExpressionCfgBuilder::VisitConditional(Conditional* expr) { | |
| 265 BAILOUT("Conditional"); | |
| 266 } | |
| 267 | |
| 268 | |
| 269 void ExpressionCfgBuilder::VisitSlot(Slot* expr) { | |
| 270 BAILOUT("Slot"); | |
| 271 } | |
| 272 | |
| 273 | |
| 274 void ExpressionCfgBuilder::VisitVariableProxy(VariableProxy* expr) { | |
| 275 Expression* rewrite = expr->var()->rewrite(); | |
| 276 if (rewrite == NULL || rewrite->AsSlot() == NULL) { | |
| 277 BAILOUT("unsupported variable (not a slot)"); | |
| 278 } | |
| 279 Slot* slot = rewrite->AsSlot(); | |
| 280 if (slot->type() != Slot::PARAMETER && slot->type() != Slot::LOCAL) { | |
| 281 BAILOUT("unsupported slot type (not a parameter or local)"); | |
| 282 } | |
| 283 // Ignore the passed destination. | |
| 284 value_ = new SlotLocation(slot->type(), slot->index()); | |
| 285 } | |
| 286 | |
| 287 | |
| 288 void ExpressionCfgBuilder::VisitLiteral(Literal* expr) { | |
| 289 // Ignore the passed destination. | |
| 290 value_ = new Constant(expr->handle()); | |
| 291 } | |
| 292 | |
| 293 | |
| 294 void ExpressionCfgBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { | |
| 295 BAILOUT("RegExpLiteral"); | |
| 296 } | |
| 297 | |
| 298 | |
| 299 void ExpressionCfgBuilder::VisitObjectLiteral(ObjectLiteral* expr) { | |
| 300 BAILOUT("ObjectLiteral"); | |
| 301 } | |
| 302 | |
| 303 | |
| 304 void ExpressionCfgBuilder::VisitArrayLiteral(ArrayLiteral* expr) { | |
| 305 BAILOUT("ArrayLiteral"); | |
| 306 } | |
| 307 | |
| 308 | |
| 309 void ExpressionCfgBuilder::VisitCatchExtensionObject( | |
| 310 CatchExtensionObject* expr) { | |
| 311 BAILOUT("CatchExtensionObject"); | |
| 312 } | |
| 313 | |
| 314 | |
| 315 void ExpressionCfgBuilder::VisitAssignment(Assignment* expr) { | |
| 316 if (expr->op() != Token::ASSIGN && expr->op() != Token::INIT_VAR) { | |
| 317 BAILOUT("unsupported compound assignment"); | |
| 318 } | |
| 319 Expression* lhs = expr->target(); | |
| 320 if (lhs->AsProperty() != NULL) { | |
| 321 BAILOUT("unsupported property assignment"); | |
| 322 } | |
| 323 | |
| 324 Variable* var = lhs->AsVariableProxy()->AsVariable(); | |
| 325 if (var == NULL) { | |
| 326 BAILOUT("unsupported invalid left-hand side"); | |
| 327 } | |
| 328 if (var->is_global()) { | |
| 329 BAILOUT("unsupported global variable"); | |
| 330 } | |
| 331 Slot* slot = var->slot(); | |
| 332 ASSERT(slot != NULL); | |
| 333 if (slot->type() != Slot::PARAMETER && slot->type() != Slot::LOCAL) { | |
| 334 BAILOUT("unsupported slot lhs (not a parameter or local)"); | |
| 335 } | |
| 336 | |
| 337 // Parameter and local slot assignments. | |
| 338 ExpressionCfgBuilder builder; | |
| 339 SlotLocation* loc = new SlotLocation(slot->type(), slot->index()); | |
| 340 builder.Build(expr->value(), loc); | |
| 341 if (builder.graph() == NULL) { | |
| 342 BAILOUT("unsupported expression in assignment"); | |
| 343 } | |
| 344 // If the expression did not come back in the slot location, append | |
| 345 // a move to the CFG. | |
| 346 graph_ = builder.graph(); | |
| 347 if (builder.value() != loc) { | |
| 348 graph()->Append(new MoveInstr(loc, builder.value())); | |
| 349 } | |
| 350 // Record the assignment. | |
| 351 assigned_vars_.AddElement(loc); | |
| 352 // Ignore the destination passed to us. | |
| 353 value_ = loc; | |
| 354 } | |
| 355 | |
| 356 | |
| 357 void ExpressionCfgBuilder::VisitThrow(Throw* expr) { | |
| 358 BAILOUT("Throw"); | |
| 359 } | |
| 360 | |
| 361 | |
| 362 void ExpressionCfgBuilder::VisitProperty(Property* expr) { | |
| 363 ExpressionCfgBuilder object, key; | |
| 364 object.Build(expr->obj(), NULL); | |
| 365 if (object.graph() == NULL) { | |
| 366 BAILOUT("unsupported object subexpression in propload"); | |
| 367 } | |
| 368 key.Build(expr->key(), NULL); | |
| 369 if (key.graph() == NULL) { | |
| 370 BAILOUT("unsupported key subexpression in propload"); | |
| 371 } | |
| 372 | |
| 373 if (destination_ == NULL) destination_ = new TempLocation(); | |
| 374 | |
| 375 graph_ = object.graph(); | |
| 376 // Insert a move to a fresh temporary if the object value is in a slot | |
| 377 // that's assigned in the key. | |
| 378 Location* temp = NULL; | |
| 379 if (object.value()->is_slot() && | |
| 380 key.assigned_vars()->Contains(SlotLocation::cast(object.value()))) { | |
| 381 temp = new TempLocation(); | |
| 382 graph()->Append(new MoveInstr(temp, object.value())); | |
| 383 } | |
| 384 graph()->Concatenate(key.graph()); | |
| 385 graph()->Append(new PropLoadInstr(destination_, | |
| 386 temp == NULL ? object.value() : temp, | |
| 387 key.value())); | |
| 388 | |
| 389 assigned_vars_ = *object.assigned_vars(); | |
| 390 assigned_vars()->Union(key.assigned_vars()); | |
| 391 | |
| 392 value_ = destination_; | |
| 393 } | |
| 394 | |
| 395 | |
| 396 void ExpressionCfgBuilder::VisitCall(Call* expr) { | |
| 397 BAILOUT("Call"); | |
| 398 } | |
| 399 | |
| 400 | |
| 401 void ExpressionCfgBuilder::VisitCallNew(CallNew* expr) { | |
| 402 BAILOUT("CallNew"); | |
| 403 } | |
| 404 | |
| 405 | |
| 406 void ExpressionCfgBuilder::VisitCallRuntime(CallRuntime* expr) { | |
| 407 BAILOUT("CallRuntime"); | |
| 408 } | |
| 409 | |
| 410 | |
| 411 void ExpressionCfgBuilder::VisitUnaryOperation(UnaryOperation* expr) { | |
| 412 BAILOUT("UnaryOperation"); | |
| 413 } | |
| 414 | |
| 415 | |
| 416 void ExpressionCfgBuilder::VisitCountOperation(CountOperation* expr) { | |
| 417 BAILOUT("CountOperation"); | |
| 418 } | |
| 419 | |
| 420 | |
| 421 void ExpressionCfgBuilder::VisitBinaryOperation(BinaryOperation* expr) { | |
| 422 Token::Value op = expr->op(); | |
| 423 switch (op) { | |
| 424 case Token::COMMA: | |
| 425 case Token::OR: | |
| 426 case Token::AND: | |
| 427 BAILOUT("unsupported binary operation"); | |
| 428 | |
| 429 case Token::BIT_OR: | |
| 430 case Token::BIT_XOR: | |
| 431 case Token::BIT_AND: | |
| 432 case Token::SHL: | |
| 433 case Token::SAR: | |
| 434 case Token::SHR: | |
| 435 case Token::ADD: | |
| 436 case Token::SUB: | |
| 437 case Token::MUL: | |
| 438 case Token::DIV: | |
| 439 case Token::MOD: { | |
| 440 ExpressionCfgBuilder left, right; | |
| 441 left.Build(expr->left(), NULL); | |
| 442 if (left.graph() == NULL) { | |
| 443 BAILOUT("unsupported left subexpression in binop"); | |
| 444 } | |
| 445 right.Build(expr->right(), NULL); | |
| 446 if (right.graph() == NULL) { | |
| 447 BAILOUT("unsupported right subexpression in binop"); | |
| 448 } | |
| 449 | |
| 450 if (destination_ == NULL) destination_ = new TempLocation(); | |
| 451 | |
| 452 graph_ = left.graph(); | |
| 453 // Insert a move to a fresh temporary if the left value is in a | |
| 454 // slot that's assigned on the right. | |
| 455 Location* temp = NULL; | |
| 456 if (left.value()->is_slot() && | |
| 457 right.assigned_vars()->Contains(SlotLocation::cast(left.value()))) { | |
| 458 temp = new TempLocation(); | |
| 459 graph()->Append(new MoveInstr(temp, left.value())); | |
| 460 } | |
| 461 graph()->Concatenate(right.graph()); | |
| 462 graph()->Append(new BinaryOpInstr(destination_, op, | |
| 463 temp == NULL ? left.value() : temp, | |
| 464 right.value())); | |
| 465 | |
| 466 assigned_vars_ = *left.assigned_vars(); | |
| 467 assigned_vars()->Union(right.assigned_vars()); | |
| 468 | |
| 469 value_ = destination_; | |
| 470 return; | |
| 471 } | |
| 472 | |
| 473 default: | |
| 474 UNREACHABLE(); | |
| 475 } | |
| 476 } | |
| 477 | |
| 478 | |
| 479 void ExpressionCfgBuilder::VisitCompareOperation(CompareOperation* expr) { | |
| 480 BAILOUT("CompareOperation"); | |
| 481 } | |
| 482 | |
| 483 | |
| 484 void ExpressionCfgBuilder::VisitThisFunction(ThisFunction* expr) { | |
| 485 BAILOUT("ThisFunction"); | |
| 486 } | |
| 487 | |
| 488 #undef BAILOUT | |
| 489 | |
| 490 | |
| 491 // Macros (temporarily) handling unsupported statement types. | |
| 492 #define BAILOUT(reason) \ | |
| 493 do { \ | |
| 494 graph_ = NULL; \ | |
| 495 return; \ | |
| 496 } while (false) | |
| 497 | |
| 498 #define CHECK_BAILOUT() \ | |
| 499 if (graph() == NULL) { return; } else {} | |
| 500 | |
| 501 void StatementCfgBuilder::VisitStatements(ZoneList<Statement*>* stmts) { | |
| 502 for (int i = 0, len = stmts->length(); i < len; i++) { | |
| 503 Visit(stmts->at(i)); | |
| 504 CHECK_BAILOUT(); | |
| 505 if (!graph()->has_exit()) return; | |
| 506 } | |
| 507 } | |
| 508 | |
| 509 | |
| 510 // The statement builder should not be used for declarations or expressions. | |
| 511 void StatementCfgBuilder::VisitDeclaration(Declaration* decl) { UNREACHABLE(); } | |
| 512 | |
| 513 #define DEFINE_VISIT(type) \ | |
| 514 void StatementCfgBuilder::Visit##type(type* expr) { UNREACHABLE(); } | |
| 515 EXPRESSION_NODE_LIST(DEFINE_VISIT) | |
| 516 #undef DEFINE_VISIT | |
| 517 | |
| 518 | |
| 519 void StatementCfgBuilder::VisitBlock(Block* stmt) { | |
| 520 VisitStatements(stmt->statements()); | |
| 521 } | |
| 522 | |
| 523 | |
| 524 void StatementCfgBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { | |
| 525 ExpressionCfgBuilder builder; | |
| 526 builder.Build(stmt->expression(), CfgGlobals::current()->nowhere()); | |
| 527 if (builder.graph() == NULL) { | |
| 528 BAILOUT("unsupported expression in expression statement"); | |
| 529 } | |
| 530 graph()->Append(new PositionInstr(stmt->statement_pos())); | |
| 531 graph()->Concatenate(builder.graph()); | |
| 532 } | |
| 533 | |
| 534 | |
| 535 void StatementCfgBuilder::VisitEmptyStatement(EmptyStatement* stmt) { | |
| 536 // Nothing to do. | |
| 537 } | |
| 538 | |
| 539 | |
| 540 void StatementCfgBuilder::VisitIfStatement(IfStatement* stmt) { | |
| 541 BAILOUT("IfStatement"); | |
| 542 } | |
| 543 | |
| 544 | |
| 545 void StatementCfgBuilder::VisitContinueStatement(ContinueStatement* stmt) { | |
| 546 BAILOUT("ContinueStatement"); | |
| 547 } | |
| 548 | |
| 549 | |
| 550 void StatementCfgBuilder::VisitBreakStatement(BreakStatement* stmt) { | |
| 551 BAILOUT("BreakStatement"); | |
| 552 } | |
| 553 | |
| 554 | |
| 555 void StatementCfgBuilder::VisitReturnStatement(ReturnStatement* stmt) { | |
| 556 ExpressionCfgBuilder builder; | |
| 557 builder.Build(stmt->expression(), NULL); | |
| 558 if (builder.graph() == NULL) { | |
| 559 BAILOUT("unsupported expression in return statement"); | |
| 560 } | |
| 561 | |
| 562 graph()->Append(new PositionInstr(stmt->statement_pos())); | |
| 563 graph()->Concatenate(builder.graph()); | |
| 564 graph()->AppendReturnInstruction(builder.value()); | |
| 565 } | |
| 566 | |
| 567 | |
| 568 void StatementCfgBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { | |
| 569 BAILOUT("WithEnterStatement"); | |
| 570 } | |
| 571 | |
| 572 | |
| 573 void StatementCfgBuilder::VisitWithExitStatement(WithExitStatement* stmt) { | |
| 574 BAILOUT("WithExitStatement"); | |
| 575 } | |
| 576 | |
| 577 | |
| 578 void StatementCfgBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | |
| 579 BAILOUT("SwitchStatement"); | |
| 580 } | |
| 581 | |
| 582 | |
| 583 void StatementCfgBuilder::VisitLoopStatement(LoopStatement* stmt) { | |
| 584 BAILOUT("LoopStatement"); | |
| 585 } | |
| 586 | |
| 587 | |
| 588 void StatementCfgBuilder::VisitForInStatement(ForInStatement* stmt) { | |
| 589 BAILOUT("ForInStatement"); | |
| 590 } | |
| 591 | |
| 592 | |
| 593 void StatementCfgBuilder::VisitTryCatch(TryCatch* stmt) { | |
| 594 BAILOUT("TryCatch"); | |
| 595 } | |
| 596 | |
| 597 | |
| 598 void StatementCfgBuilder::VisitTryFinally(TryFinally* stmt) { | |
| 599 BAILOUT("TryFinally"); | |
| 600 } | |
| 601 | |
| 602 | |
| 603 void StatementCfgBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { | |
| 604 BAILOUT("DebuggerStatement"); | |
| 605 } | |
| 606 | |
| 607 | |
| 608 #ifdef DEBUG | |
| 609 // CFG printing support (via depth-first, preorder block traversal). | |
| 610 | |
| 611 void Cfg::Print() { | |
| 612 entry_->Print(); | |
| 613 entry_->Unmark(); | |
| 614 } | |
| 615 | |
| 616 | |
| 617 void Constant::Print() { | |
| 618 PrintF("Constant "); | |
| 619 handle_->Print(); | |
| 620 } | |
| 621 | |
| 622 | |
| 623 void Nowhere::Print() { | |
| 624 PrintF("Nowhere"); | |
| 625 } | |
| 626 | |
| 627 | |
| 628 void SlotLocation::Print() { | |
| 629 PrintF("Slot "); | |
| 630 switch (type_) { | |
| 631 case Slot::PARAMETER: | |
| 632 PrintF("(PARAMETER, %d)", index_); | |
| 633 break; | |
| 634 case Slot::LOCAL: | |
| 635 PrintF("(LOCAL, %d)", index_); | |
| 636 break; | |
| 637 default: | |
| 638 UNREACHABLE(); | |
| 639 } | |
| 640 } | |
| 641 | |
| 642 | |
| 643 void TempLocation::Print() { | |
| 644 PrintF("Temp %d", number()); | |
| 645 } | |
| 646 | |
| 647 | |
| 648 void OneOperandInstruction::Print() { | |
| 649 PrintF("("); | |
| 650 location()->Print(); | |
| 651 PrintF(", "); | |
| 652 value_->Print(); | |
| 653 PrintF(")"); | |
| 654 } | |
| 655 | |
| 656 | |
| 657 void TwoOperandInstruction::Print() { | |
| 658 PrintF("("); | |
| 659 location()->Print(); | |
| 660 PrintF(", "); | |
| 661 value0_->Print(); | |
| 662 PrintF(", "); | |
| 663 value1_->Print(); | |
| 664 PrintF(")"); | |
| 665 } | |
| 666 | |
| 667 | |
| 668 void MoveInstr::Print() { | |
| 669 PrintF("Move "); | |
| 670 OneOperandInstruction::Print(); | |
| 671 PrintF("\n"); | |
| 672 } | |
| 673 | |
| 674 | |
| 675 void PropLoadInstr::Print() { | |
| 676 PrintF("PropLoad "); | |
| 677 TwoOperandInstruction::Print(); | |
| 678 PrintF("\n"); | |
| 679 } | |
| 680 | |
| 681 | |
| 682 void BinaryOpInstr::Print() { | |
| 683 switch (op()) { | |
| 684 case Token::OR: | |
| 685 // Two character operand. | |
| 686 PrintF("BinaryOp[OR] "); | |
| 687 break; | |
| 688 case Token::AND: | |
| 689 case Token::SHL: | |
| 690 case Token::SAR: | |
| 691 case Token::SHR: | |
| 692 case Token::ADD: | |
| 693 case Token::SUB: | |
| 694 case Token::MUL: | |
| 695 case Token::DIV: | |
| 696 case Token::MOD: | |
| 697 // Three character operands. | |
| 698 PrintF("BinaryOp[%s] ", Token::Name(op())); | |
| 699 break; | |
| 700 case Token::COMMA: | |
| 701 // Five character operand. | |
| 702 PrintF("BinaryOp[COMMA] "); | |
| 703 break; | |
| 704 case Token::BIT_OR: | |
| 705 // Six character operand. | |
| 706 PrintF("BinaryOp[BIT_OR] "); | |
| 707 break; | |
| 708 case Token::BIT_XOR: | |
| 709 case Token::BIT_AND: | |
| 710 // Seven character operands. | |
| 711 PrintF("BinaryOp[%s] ", Token::Name(op())); | |
| 712 break; | |
| 713 default: | |
| 714 UNREACHABLE(); | |
| 715 } | |
| 716 TwoOperandInstruction::Print(); | |
| 717 PrintF("\n"); | |
| 718 } | |
| 719 | |
| 720 | |
| 721 void ReturnInstr::Print() { | |
| 722 PrintF("Return "); | |
| 723 OneOperandInstruction::Print(); | |
| 724 PrintF("\n"); | |
| 725 } | |
| 726 | |
| 727 | |
| 728 void InstructionBlock::Print() { | |
| 729 if (!is_marked_) { | |
| 730 is_marked_ = true; | |
| 731 PrintF("L%d:\n", number()); | |
| 732 for (int i = 0, len = instructions_.length(); i < len; i++) { | |
| 733 instructions_[i]->Print(); | |
| 734 } | |
| 735 PrintF("Goto L%d\n\n", successor_->number()); | |
| 736 successor_->Print(); | |
| 737 } | |
| 738 } | |
| 739 | |
| 740 | |
| 741 void EntryNode::Print() { | |
| 742 if (!is_marked_) { | |
| 743 is_marked_ = true; | |
| 744 successor_->Print(); | |
| 745 } | |
| 746 } | |
| 747 | |
| 748 | |
| 749 void ExitNode::Print() { | |
| 750 if (!is_marked_) { | |
| 751 is_marked_ = true; | |
| 752 PrintF("L%d:\nExit\n\n", number()); | |
| 753 } | |
| 754 } | |
| 755 | |
| 756 #endif // DEBUG | |
| 757 | |
| 758 } } // namespace v8::internal | |
| OLD | NEW |