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 ExitNode* Cfg::global_exit_ = NULL; |
| 40 |
| 41 |
| 42 void CfgNode::Reset() { |
| 43 #ifdef DEBUG |
| 44 node_counter_ = 0; |
| 45 #endif |
| 46 } |
| 47 |
| 48 |
| 49 void Cfg::Reset(FunctionLiteral* fun) { |
| 50 global_exit_ = new ExitNode(fun); |
| 51 CfgNode::Reset(); |
| 52 } |
| 53 |
| 54 |
| 55 #define BAILOUT(reason) \ |
| 56 do { return NULL; } while (false) |
| 57 |
| 58 Cfg* Cfg::Build(FunctionLiteral* fun) { |
| 59 ZoneList<Statement*>* body = fun->body(); |
| 60 if (body->is_empty()) { |
| 61 BAILOUT("empty function body"); |
| 62 } |
| 63 |
| 64 Cfg::Reset(fun); |
| 65 StatementBuilder builder; |
| 66 builder.VisitStatements(body); |
| 67 Cfg* cfg = builder.cfg(); |
| 68 if (cfg == NULL) { |
| 69 BAILOUT("unsupported statement type"); |
| 70 } |
| 71 |
| 72 ASSERT(!cfg->has_exit()); // Return on all paths. |
| 73 cfg->PrependEntryNode(fun); |
| 74 return cfg; |
| 75 } |
| 76 |
| 77 #undef BAILOUT |
| 78 |
| 79 |
| 80 void Cfg::PrependEntryNode(FunctionLiteral* fun) { |
| 81 ASSERT(!is_empty()); |
| 82 entry_ = new EntryNode(fun, InstructionBlock::cast(entry())); |
| 83 } |
| 84 |
| 85 |
| 86 void Cfg::Append(Instruction* instr) { |
| 87 ASSERT(has_exit()); |
| 88 ASSERT(!is_empty()); |
| 89 InstructionBlock::cast(exit_)->Append(instr); |
| 90 } |
| 91 |
| 92 |
| 93 void Cfg::AppendReturnInstruction(Value* value) { |
| 94 Append(new ReturnInstr(value)); |
| 95 InstructionBlock::cast(exit_)->set_successor(global_exit_); |
| 96 exit_ = NULL; |
| 97 } |
| 98 |
| 99 |
| 100 EntryNode::EntryNode(FunctionLiteral* fun, InstructionBlock* succ) |
| 101 : successor_(succ), local_count_(fun->scope()->num_stack_slots()) { |
| 102 } |
| 103 |
| 104 |
| 105 ExitNode::ExitNode(FunctionLiteral* fun) |
| 106 : parameter_count_(fun->scope()->num_parameters()) { |
| 107 } |
| 108 |
| 109 |
| 110 void InstructionBlock::Unmark() { |
| 111 if (is_marked_) { |
| 112 is_marked_ = false; |
| 113 successor_->Unmark(); |
| 114 } |
| 115 } |
| 116 |
| 117 |
| 118 void EntryNode::Unmark() { |
| 119 if (is_marked_) { |
| 120 is_marked_ = false; |
| 121 successor_->Unmark(); |
| 122 } |
| 123 } |
| 124 |
| 125 |
| 126 void ExitNode::Unmark() {} |
| 127 |
| 128 |
| 129 Handle<Code> Cfg::Compile(FunctionLiteral* fun, Handle<Script> script) { |
| 130 const int kInitialBufferSize = 4 * KB; |
| 131 MacroAssembler* masm = new MacroAssembler(NULL, kInitialBufferSize); |
| 132 entry()->Compile(masm); |
| 133 entry()->Unmark(); |
| 134 CodeDesc desc; |
| 135 masm->GetCode(&desc); |
| 136 ZoneScopeInfo info(fun->scope()); |
| 137 InLoopFlag in_loop = fun->loop_nesting() ? IN_LOOP : NOT_IN_LOOP; |
| 138 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop); |
| 139 Handle<Code> code = Factory::NewCode(desc, &info, flags, masm->CodeObject()); |
| 140 |
| 141 // Add unresolved entries in the code to the fixup list. |
| 142 Bootstrapper::AddFixup(*code, masm); |
| 143 |
| 144 #ifdef ENABLE_DISASSEMBLER |
| 145 if (FLAG_print_code) { |
| 146 // Print the source code if available. |
| 147 if (!script->IsUndefined() && !script->source()->IsUndefined()) { |
| 148 PrintF("--- Raw source ---\n"); |
| 149 StringInputBuffer stream(String::cast(script->source())); |
| 150 stream.Seek(fun->start_position()); |
| 151 // fun->end_position() points to the last character in the stream. We |
| 152 // need to compensate by adding one to calculate the length. |
| 153 int source_len = fun->end_position() - fun->start_position() + 1; |
| 154 for (int i = 0; i < source_len; i++) { |
| 155 if (stream.has_more()) PrintF("%c", stream.GetNext()); |
| 156 } |
| 157 PrintF("\n\n"); |
| 158 } |
| 159 PrintF("--- Code ---\n"); |
| 160 code->Disassemble(*fun->name()->ToCString()); |
| 161 } |
| 162 #endif |
| 163 |
| 164 return code; |
| 165 } |
| 166 |
| 167 |
| 168 // The expression builder should not be used for declarations or statements. |
| 169 void ExpressionBuilder::VisitDeclaration(Declaration* decl) { UNREACHABLE(); } |
| 170 |
| 171 #define DEFINE_VISIT(type) \ |
| 172 void ExpressionBuilder::Visit##type(type* stmt) { UNREACHABLE(); } |
| 173 STATEMENT_NODE_LIST(DEFINE_VISIT) |
| 174 #undef DEFINE_VISIT |
| 175 |
| 176 |
| 177 // Macros (temporarily) handling unsupported expression types. |
| 178 #define BAILOUT(reason) \ |
| 179 do { \ |
| 180 value_ = NULL; \ |
| 181 return; \ |
| 182 } while (false) |
| 183 |
| 184 #define CHECK_BAILOUT() \ |
| 185 if (value_ == NULL) { return; } else {} |
| 186 |
| 187 void ExpressionBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 188 BAILOUT("FunctionLiteral"); |
| 189 } |
| 190 |
| 191 |
| 192 void ExpressionBuilder::VisitFunctionBoilerplateLiteral( |
| 193 FunctionBoilerplateLiteral* expr) { |
| 194 BAILOUT("FunctionBoilerplateLiteral"); |
| 195 } |
| 196 |
| 197 |
| 198 void ExpressionBuilder::VisitConditional(Conditional* expr) { |
| 199 BAILOUT("Conditional"); |
| 200 } |
| 201 |
| 202 |
| 203 void ExpressionBuilder::VisitSlot(Slot* expr) { |
| 204 BAILOUT("Slot"); |
| 205 } |
| 206 |
| 207 |
| 208 void ExpressionBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 209 BAILOUT("VariableProxy"); |
| 210 } |
| 211 |
| 212 |
| 213 void ExpressionBuilder::VisitLiteral(Literal* expr) { |
| 214 value_ = new Constant(expr->handle()); |
| 215 } |
| 216 |
| 217 |
| 218 void ExpressionBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 219 BAILOUT("RegExpLiteral"); |
| 220 } |
| 221 |
| 222 |
| 223 void ExpressionBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
| 224 BAILOUT("ObjectLiteral"); |
| 225 } |
| 226 |
| 227 |
| 228 void ExpressionBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
| 229 BAILOUT("ArrayLiteral"); |
| 230 } |
| 231 |
| 232 |
| 233 void ExpressionBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
| 234 BAILOUT("CatchExtensionObject"); |
| 235 } |
| 236 |
| 237 |
| 238 void ExpressionBuilder::VisitAssignment(Assignment* expr) { |
| 239 BAILOUT("Assignment"); |
| 240 } |
| 241 |
| 242 |
| 243 void ExpressionBuilder::VisitThrow(Throw* expr) { |
| 244 BAILOUT("Throw"); |
| 245 } |
| 246 |
| 247 |
| 248 void ExpressionBuilder::VisitProperty(Property* expr) { |
| 249 BAILOUT("Property"); |
| 250 } |
| 251 |
| 252 |
| 253 void ExpressionBuilder::VisitCall(Call* expr) { |
| 254 BAILOUT("Call"); |
| 255 } |
| 256 |
| 257 |
| 258 void ExpressionBuilder::VisitCallEval(CallEval* expr) { |
| 259 BAILOUT("CallEval"); |
| 260 } |
| 261 |
| 262 |
| 263 void ExpressionBuilder::VisitCallNew(CallNew* expr) { |
| 264 BAILOUT("CallNew"); |
| 265 } |
| 266 |
| 267 |
| 268 void ExpressionBuilder::VisitCallRuntime(CallRuntime* expr) { |
| 269 BAILOUT("CallRuntime"); |
| 270 } |
| 271 |
| 272 |
| 273 void ExpressionBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 274 BAILOUT("UnaryOperation"); |
| 275 } |
| 276 |
| 277 |
| 278 void ExpressionBuilder::VisitCountOperation(CountOperation* expr) { |
| 279 BAILOUT("CountOperation"); |
| 280 } |
| 281 |
| 282 |
| 283 void ExpressionBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
| 284 BAILOUT("BinaryOperation"); |
| 285 } |
| 286 |
| 287 |
| 288 void ExpressionBuilder::VisitCompareOperation(CompareOperation* expr) { |
| 289 BAILOUT("CompareOperation"); |
| 290 } |
| 291 |
| 292 |
| 293 void ExpressionBuilder::VisitThisFunction(ThisFunction* expr) { |
| 294 BAILOUT("ThisFunction"); |
| 295 } |
| 296 |
| 297 #undef BAILOUT |
| 298 #undef CHECK_BAILOUT |
| 299 |
| 300 |
| 301 // Macros (temporarily) handling unsupported statement types. |
| 302 #define BAILOUT(reason) \ |
| 303 do { \ |
| 304 cfg_ = NULL; \ |
| 305 return; \ |
| 306 } while (false) |
| 307 |
| 308 #define CHECK_BAILOUT() \ |
| 309 if (cfg_ == NULL) { return; } else {} |
| 310 |
| 311 void StatementBuilder::VisitStatements(ZoneList<Statement*>* stmts) { |
| 312 for (int i = 0, len = stmts->length(); i < len; i++) { |
| 313 Visit(stmts->at(i)); |
| 314 CHECK_BAILOUT(); |
| 315 if (!cfg_->has_exit()) return; |
| 316 } |
| 317 } |
| 318 |
| 319 |
| 320 // The statement builder should not be used for declarations or expressions. |
| 321 void StatementBuilder::VisitDeclaration(Declaration* decl) { UNREACHABLE(); } |
| 322 |
| 323 #define DEFINE_VISIT(type) \ |
| 324 void StatementBuilder::Visit##type(type* expr) { UNREACHABLE(); } |
| 325 EXPRESSION_NODE_LIST(DEFINE_VISIT) |
| 326 #undef DEFINE_VISIT |
| 327 |
| 328 |
| 329 void StatementBuilder::VisitBlock(Block* stmt) { |
| 330 VisitStatements(stmt->statements()); |
| 331 } |
| 332 |
| 333 |
| 334 void StatementBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { |
| 335 BAILOUT("ExpressionStatement"); |
| 336 } |
| 337 |
| 338 |
| 339 void StatementBuilder::VisitEmptyStatement(EmptyStatement* stmt) { |
| 340 // Nothing to do. |
| 341 } |
| 342 |
| 343 |
| 344 void StatementBuilder::VisitIfStatement(IfStatement* stmt) { |
| 345 BAILOUT("IfStatement"); |
| 346 } |
| 347 |
| 348 |
| 349 void StatementBuilder::VisitContinueStatement(ContinueStatement* stmt) { |
| 350 BAILOUT("ContinueStatement"); |
| 351 } |
| 352 |
| 353 |
| 354 void StatementBuilder::VisitBreakStatement(BreakStatement* stmt) { |
| 355 BAILOUT("BreakStatement"); |
| 356 } |
| 357 |
| 358 |
| 359 void StatementBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
| 360 ExpressionBuilder builder; |
| 361 builder.Visit(stmt->expression()); |
| 362 Value* value = builder.value(); |
| 363 if (value == NULL) BAILOUT("unsupported expression type"); |
| 364 cfg_->AppendReturnInstruction(value); |
| 365 } |
| 366 |
| 367 |
| 368 void StatementBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { |
| 369 BAILOUT("WithEnterStatement"); |
| 370 } |
| 371 |
| 372 |
| 373 void StatementBuilder::VisitWithExitStatement(WithExitStatement* stmt) { |
| 374 BAILOUT("WithExitStatement"); |
| 375 } |
| 376 |
| 377 |
| 378 void StatementBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 379 BAILOUT("SwitchStatement"); |
| 380 } |
| 381 |
| 382 |
| 383 void StatementBuilder::VisitLoopStatement(LoopStatement* stmt) { |
| 384 BAILOUT("LoopStatement"); |
| 385 } |
| 386 |
| 387 |
| 388 void StatementBuilder::VisitForInStatement(ForInStatement* stmt) { |
| 389 BAILOUT("ForInStatement"); |
| 390 } |
| 391 |
| 392 |
| 393 void StatementBuilder::VisitTryCatch(TryCatch* stmt) { |
| 394 BAILOUT("TryCatch"); |
| 395 } |
| 396 |
| 397 |
| 398 void StatementBuilder::VisitTryFinally(TryFinally* stmt) { |
| 399 BAILOUT("TryFinally"); |
| 400 } |
| 401 |
| 402 |
| 403 void StatementBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { |
| 404 BAILOUT("DebuggerStatement"); |
| 405 } |
| 406 |
| 407 |
| 408 #ifdef DEBUG |
| 409 // CFG printing support (via depth-first, preorder block traversal). |
| 410 |
| 411 void Cfg::Print() { |
| 412 entry_->Print(); |
| 413 entry_->Unmark(); |
| 414 } |
| 415 |
| 416 |
| 417 void Constant::Print() { |
| 418 handle_->Print(); |
| 419 } |
| 420 |
| 421 |
| 422 void ReturnInstr::Print() { |
| 423 PrintF("Return "); |
| 424 value_->Print(); |
| 425 PrintF("\n"); |
| 426 } |
| 427 |
| 428 |
| 429 int CfgNode::node_counter_ = 0; |
| 430 |
| 431 |
| 432 void InstructionBlock::Print() { |
| 433 if (!is_marked_) { |
| 434 is_marked_ = true; |
| 435 PrintF("L%d:\n", number()); |
| 436 for (int i = 0, len = instructions_.length(); i < len; i++) { |
| 437 instructions_[i]->Print(); |
| 438 } |
| 439 PrintF("Goto L%d\n\n", successor_->number()); |
| 440 successor_->Print(); |
| 441 } |
| 442 } |
| 443 |
| 444 |
| 445 void EntryNode::Print() { |
| 446 if (!is_marked_) { |
| 447 is_marked_ = true; |
| 448 successor_->Print(); |
| 449 } |
| 450 } |
| 451 |
| 452 |
| 453 void ExitNode::Print() { |
| 454 if (!is_marked_) { |
| 455 is_marked_ = true; |
| 456 PrintF("L%d:\nExit\n\n", number()); |
| 457 } |
| 458 } |
| 459 |
| 460 #endif // DEBUG |
| 461 |
| 462 } } // namespace v8::internal |
OLD | NEW |