| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 | 52 |
| 53 namespace v8 { | 53 namespace v8 { |
| 54 namespace internal { | 54 namespace internal { |
| 55 | 55 |
| 56 | 56 |
| 57 CompilationInfo::CompilationInfo(Handle<Script> script, | 57 CompilationInfo::CompilationInfo(Handle<Script> script, |
| 58 Zone* zone) | 58 Zone* zone) |
| 59 : flags_(LanguageModeField::encode(CLASSIC_MODE)), | 59 : flags_(LanguageModeField::encode(CLASSIC_MODE)), |
| 60 script_(script), | 60 script_(script), |
| 61 osr_ast_id_(BailoutId::None()), | 61 osr_ast_id_(BailoutId::None()), |
| 62 osr_pc_offset_(0), | |
| 63 parameter_count_(0) { | 62 parameter_count_(0) { |
| 64 Initialize(script->GetIsolate(), BASE, zone); | 63 Initialize(script->GetIsolate(), BASE, zone); |
| 65 } | 64 } |
| 66 | 65 |
| 67 | 66 |
| 68 CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info, | 67 CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info, |
| 69 Zone* zone) | 68 Zone* zone) |
| 70 : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)), | 69 : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)), |
| 71 shared_info_(shared_info), | 70 shared_info_(shared_info), |
| 72 script_(Handle<Script>(Script::cast(shared_info->script()))), | 71 script_(Handle<Script>(Script::cast(shared_info->script()))), |
| 73 osr_ast_id_(BailoutId::None()), | 72 osr_ast_id_(BailoutId::None()), |
| 74 osr_pc_offset_(0), | |
| 75 parameter_count_(0) { | 73 parameter_count_(0) { |
| 76 Initialize(script_->GetIsolate(), BASE, zone); | 74 Initialize(script_->GetIsolate(), BASE, zone); |
| 77 } | 75 } |
| 78 | 76 |
| 79 | 77 |
| 80 CompilationInfo::CompilationInfo(Handle<JSFunction> closure, | 78 CompilationInfo::CompilationInfo(Handle<JSFunction> closure, |
| 81 Zone* zone) | 79 Zone* zone) |
| 82 : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)), | 80 : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)), |
| 83 closure_(closure), | 81 closure_(closure), |
| 84 shared_info_(Handle<SharedFunctionInfo>(closure->shared())), | 82 shared_info_(Handle<SharedFunctionInfo>(closure->shared())), |
| 85 script_(Handle<Script>(Script::cast(shared_info_->script()))), | 83 script_(Handle<Script>(Script::cast(shared_info_->script()))), |
| 86 context_(closure->context()), | 84 context_(closure->context()), |
| 87 osr_ast_id_(BailoutId::None()), | 85 osr_ast_id_(BailoutId::None()), |
| 88 osr_pc_offset_(0), | |
| 89 parameter_count_(0) { | 86 parameter_count_(0) { |
| 90 Initialize(script_->GetIsolate(), BASE, zone); | 87 Initialize(script_->GetIsolate(), BASE, zone); |
| 91 } | 88 } |
| 92 | 89 |
| 93 | 90 |
| 94 CompilationInfo::CompilationInfo(HydrogenCodeStub* stub, | 91 CompilationInfo::CompilationInfo(HydrogenCodeStub* stub, |
| 95 Isolate* isolate, | 92 Isolate* isolate, |
| 96 Zone* zone) | 93 Zone* zone) |
| 97 : flags_(LanguageModeField::encode(CLASSIC_MODE) | | 94 : flags_(LanguageModeField::encode(CLASSIC_MODE) | |
| 98 IsLazy::encode(true)), | 95 IsLazy::encode(true)), |
| 99 osr_ast_id_(BailoutId::None()), | 96 osr_ast_id_(BailoutId::None()), |
| 100 osr_pc_offset_(0), | |
| 101 parameter_count_(0) { | 97 parameter_count_(0) { |
| 102 Initialize(isolate, STUB, zone); | 98 Initialize(isolate, STUB, zone); |
| 103 code_stub_ = stub; | 99 code_stub_ = stub; |
| 104 } | 100 } |
| 105 | 101 |
| 106 | 102 |
| 107 void CompilationInfo::Initialize(Isolate* isolate, | 103 void CompilationInfo::Initialize(Isolate* isolate, |
| 108 Mode mode, | 104 Mode mode, |
| 109 Zone* zone) { | 105 Zone* zone) { |
| 110 isolate_ = isolate; | 106 isolate_ = isolate; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 !scope_->outer_scope_calls_non_strict_eval() && | 224 !scope_->outer_scope_calls_non_strict_eval() && |
| 229 !scope_->inside_with(); | 225 !scope_->inside_with(); |
| 230 SetMode(is_optimizable_closure ? BASE : NONOPT); | 226 SetMode(is_optimizable_closure ? BASE : NONOPT); |
| 231 } | 227 } |
| 232 | 228 |
| 233 | 229 |
| 234 // Primitive functions are unlikely to be picked up by the stack-walking | 230 // Primitive functions are unlikely to be picked up by the stack-walking |
| 235 // profiler, so they trigger their own optimization when they're called | 231 // profiler, so they trigger their own optimization when they're called |
| 236 // for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time. | 232 // for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time. |
| 237 bool CompilationInfo::ShouldSelfOptimize() { | 233 bool CompilationInfo::ShouldSelfOptimize() { |
| 238 return FLAG_self_optimization && | 234 return FLAG_crankshaft && |
| 239 FLAG_crankshaft && | |
| 240 !function()->flags()->Contains(kDontSelfOptimize) && | 235 !function()->flags()->Contains(kDontSelfOptimize) && |
| 241 !function()->dont_optimize() && | 236 !function()->dont_optimize() && |
| 242 function()->scope()->AllowsLazyCompilation() && | 237 function()->scope()->AllowsLazyCompilation() && |
| 243 (shared_info().is_null() || !shared_info()->optimization_disabled()); | 238 (shared_info().is_null() || !shared_info()->optimization_disabled()); |
| 244 } | 239 } |
| 245 | 240 |
| 246 | 241 |
| 247 // Determine whether to use the full compiler for all code. If the flag | |
| 248 // --always-full-compiler is specified this is the case. For the virtual frame | |
| 249 // based compiler the full compiler is also used if a debugger is connected, as | |
| 250 // the code from the full compiler supports mode precise break points. For the | |
| 251 // crankshaft adaptive compiler debugging the optimized code is not possible at | |
| 252 // all. However crankshaft support recompilation of functions, so in this case | |
| 253 // the full compiler need not be be used if a debugger is attached, but only if | |
| 254 // break points has actually been set. | |
| 255 static bool IsDebuggerActive(Isolate* isolate) { | |
| 256 #ifdef ENABLE_DEBUGGER_SUPPORT | |
| 257 return isolate->use_crankshaft() ? | |
| 258 isolate->debug()->has_break_points() : | |
| 259 isolate->debugger()->IsDebuggerActive(); | |
| 260 #else | |
| 261 return false; | |
| 262 #endif | |
| 263 } | |
| 264 | |
| 265 | |
| 266 static bool AlwaysFullCompiler(Isolate* isolate) { | |
| 267 return FLAG_always_full_compiler || IsDebuggerActive(isolate); | |
| 268 } | |
| 269 | |
| 270 | |
| 271 void RecompileJob::RecordOptimizationStats() { | |
| 272 Handle<JSFunction> function = info()->closure(); | |
| 273 if (!function->IsOptimized()) { | |
| 274 // Concurrent recompilation and OSR may race. Increment only once. | |
| 275 int opt_count = function->shared()->opt_count(); | |
| 276 function->shared()->set_opt_count(opt_count + 1); | |
| 277 } | |
| 278 double ms_creategraph = time_taken_to_create_graph_.InMillisecondsF(); | |
| 279 double ms_optimize = time_taken_to_optimize_.InMillisecondsF(); | |
| 280 double ms_codegen = time_taken_to_codegen_.InMillisecondsF(); | |
| 281 if (FLAG_trace_opt) { | |
| 282 PrintF("[optimizing "); | |
| 283 function->ShortPrint(); | |
| 284 PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize, | |
| 285 ms_codegen); | |
| 286 } | |
| 287 if (FLAG_trace_opt_stats) { | |
| 288 static double compilation_time = 0.0; | |
| 289 static int compiled_functions = 0; | |
| 290 static int code_size = 0; | |
| 291 | |
| 292 compilation_time += (ms_creategraph + ms_optimize + ms_codegen); | |
| 293 compiled_functions++; | |
| 294 code_size += function->shared()->SourceSize(); | |
| 295 PrintF("Compiled: %d functions with %d byte source size in %fms.\n", | |
| 296 compiled_functions, | |
| 297 code_size, | |
| 298 compilation_time); | |
| 299 } | |
| 300 if (FLAG_hydrogen_stats) { | |
| 301 isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_create_graph_, | |
| 302 time_taken_to_optimize_, | |
| 303 time_taken_to_codegen_); | |
| 304 } | |
| 305 } | |
| 306 | |
| 307 | |
| 308 // A return value of true indicates the compilation pipeline is still | |
| 309 // going, not necessarily that we optimized the code. | |
| 310 static bool MakeCrankshaftCode(CompilationInfo* info) { | |
| 311 RecompileJob job(info); | |
| 312 RecompileJob::Status status = job.CreateGraph(); | |
| 313 | |
| 314 if (status != RecompileJob::SUCCEEDED) { | |
| 315 return status != RecompileJob::FAILED; | |
| 316 } | |
| 317 status = job.OptimizeGraph(); | |
| 318 if (status != RecompileJob::SUCCEEDED) { | |
| 319 status = job.AbortOptimization(); | |
| 320 return status != RecompileJob::FAILED; | |
| 321 } | |
| 322 status = job.GenerateAndInstallCode(); | |
| 323 return status != RecompileJob::FAILED; | |
| 324 } | |
| 325 | |
| 326 | |
| 327 class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder { | 242 class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder { |
| 328 public: | 243 public: |
| 329 explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info) | 244 explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info) |
| 330 : HOptimizedGraphBuilder(info) { | 245 : HOptimizedGraphBuilder(info) { |
| 331 } | 246 } |
| 332 | 247 |
| 333 #define DEF_VISIT(type) \ | 248 #define DEF_VISIT(type) \ |
| 334 virtual void Visit##type(type* node) V8_OVERRIDE { \ | 249 virtual void Visit##type(type* node) V8_OVERRIDE { \ |
| 335 if (node->position() != RelocInfo::kNoPosition) { \ | 250 if (node->position() != RelocInfo::kNoPosition) { \ |
| 336 SetSourcePosition(node->position()); \ | 251 SetSourcePosition(node->position()); \ |
| (...skipping 12 matching lines...) Expand all Loading... |
| 349 } | 264 } |
| 350 STATEMENT_NODE_LIST(DEF_VISIT) | 265 STATEMENT_NODE_LIST(DEF_VISIT) |
| 351 #undef DEF_VISIT | 266 #undef DEF_VISIT |
| 352 | 267 |
| 353 #define DEF_VISIT(type) \ | 268 #define DEF_VISIT(type) \ |
| 354 virtual void Visit##type(type* node) V8_OVERRIDE { \ | 269 virtual void Visit##type(type* node) V8_OVERRIDE { \ |
| 355 HOptimizedGraphBuilder::Visit##type(node); \ | 270 HOptimizedGraphBuilder::Visit##type(node); \ |
| 356 } | 271 } |
| 357 MODULE_NODE_LIST(DEF_VISIT) | 272 MODULE_NODE_LIST(DEF_VISIT) |
| 358 DECLARATION_NODE_LIST(DEF_VISIT) | 273 DECLARATION_NODE_LIST(DEF_VISIT) |
| 359 AUXILIARY_NODE_LIST(DEF_VISIT) | |
| 360 #undef DEF_VISIT | 274 #undef DEF_VISIT |
| 361 }; | 275 }; |
| 362 | 276 |
| 363 | 277 |
| 364 RecompileJob::Status RecompileJob::CreateGraph() { | 278 // Determine whether to use the full compiler for all code. If the flag |
| 279 // --always-full-compiler is specified this is the case. For the virtual frame |
| 280 // based compiler the full compiler is also used if a debugger is connected, as |
| 281 // the code from the full compiler supports mode precise break points. For the |
| 282 // crankshaft adaptive compiler debugging the optimized code is not possible at |
| 283 // all. However crankshaft support recompilation of functions, so in this case |
| 284 // the full compiler need not be be used if a debugger is attached, but only if |
| 285 // break points has actually been set. |
| 286 static bool IsDebuggerActive(Isolate* isolate) { |
| 287 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 288 return isolate->use_crankshaft() ? |
| 289 isolate->debug()->has_break_points() : |
| 290 isolate->debugger()->IsDebuggerActive(); |
| 291 #else |
| 292 return false; |
| 293 #endif |
| 294 } |
| 295 |
| 296 |
| 297 OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() { |
| 365 ASSERT(isolate()->use_crankshaft()); | 298 ASSERT(isolate()->use_crankshaft()); |
| 366 ASSERT(info()->IsOptimizing()); | 299 ASSERT(info()->IsOptimizing()); |
| 367 ASSERT(!info()->IsCompilingForDebugging()); | 300 ASSERT(!info()->IsCompilingForDebugging()); |
| 368 | 301 |
| 369 // We should never arrive here if there is no code object on the | 302 // We should never arrive here if there is no code object on the |
| 370 // shared function object. | 303 // shared function object. |
| 371 ASSERT(info()->shared_info()->code()->kind() == Code::FUNCTION); | 304 ASSERT(info()->shared_info()->code()->kind() == Code::FUNCTION); |
| 372 | 305 |
| 373 if (FLAG_trace_opt) { | 306 if (FLAG_trace_opt) { |
| 374 // TODO(jbramley): This was added to help analyse the behaviour of | 307 // TODO(jbramley): This was added to help analyse the behaviour of |
| 375 // Crankshaft for the A64 Crankshaft port. It should eventually be deleted. | 308 // Crankshaft for the A64 Crankshaft port. It should eventually be deleted. |
| 376 Handle<JSFunction> function = info()->closure(); | 309 Handle<JSFunction> function = info()->closure(); |
| 377 PrintF("Attempting optimization of "); | 310 PrintF("Attempting optimization of "); |
| 378 function->PrintName(); | 311 function->PrintName(); |
| 379 PrintF(" / %" V8PRIxPTR "\n", reinterpret_cast<intptr_t>(*function)); | 312 PrintF(" / %" V8PRIxPTR "\n", reinterpret_cast<intptr_t>(*function)); |
| 380 } | 313 } |
| 381 | 314 |
| 382 // We should never arrive here if optimization has been disabled on the | 315 // We should never arrive here if optimization has been disabled on the |
| 383 // shared function info. | 316 // shared function info. |
| 384 ASSERT(!info()->shared_info()->optimization_disabled()); | 317 ASSERT(!info()->shared_info()->optimization_disabled()); |
| 385 | 318 |
| 386 // Fall back to using the full code generator if it's not possible | 319 // Fall back to using the full code generator if it's not possible |
| 387 // to use the Hydrogen-based optimizing compiler. We already have | 320 // to use the Hydrogen-based optimizing compiler. We already have |
| 388 // generated code for this from the shared function object. | 321 // generated code for this from the shared function object. |
| 389 if (AlwaysFullCompiler(isolate())) { | 322 if (FLAG_always_full_compiler) return AbortOptimization(); |
| 390 info()->AbortOptimization(); | 323 if (IsDebuggerActive(isolate())) return AbortOptimization(kDebuggerIsActive); |
| 391 return SetLastStatus(BAILED_OUT); | |
| 392 } | |
| 393 | 324 |
| 394 // Limit the number of times we re-compile a functions with | 325 // Limit the number of times we re-compile a functions with |
| 395 // the optimizing compiler. | 326 // the optimizing compiler. |
| 396 const int kMaxOptCount = | 327 const int kMaxOptCount = |
| 397 FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000; | 328 FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000; |
| 398 if (info()->opt_count() > kMaxOptCount) { | 329 if (info()->opt_count() > kMaxOptCount) { |
| 399 info()->set_bailout_reason(kOptimizedTooManyTimes); | 330 return AbortAndDisableOptimization(kOptimizedTooManyTimes); |
| 400 return AbortOptimization(); | |
| 401 } | 331 } |
| 402 | 332 |
| 403 // Due to an encoding limit on LUnallocated operands in the Lithium | 333 // Due to an encoding limit on LUnallocated operands in the Lithium |
| 404 // language, we cannot optimize functions with too many formal parameters | 334 // language, we cannot optimize functions with too many formal parameters |
| 405 // or perform on-stack replacement for function with too many | 335 // or perform on-stack replacement for function with too many |
| 406 // stack-allocated local variables. | 336 // stack-allocated local variables. |
| 407 // | 337 // |
| 408 // The encoding is as a signed value, with parameters and receiver using | 338 // The encoding is as a signed value, with parameters and receiver using |
| 409 // the negative indices and locals the non-negative ones. | 339 // the negative indices and locals the non-negative ones. |
| 410 const int parameter_limit = -LUnallocated::kMinFixedSlotIndex; | 340 const int parameter_limit = -LUnallocated::kMinFixedSlotIndex; |
| 411 Scope* scope = info()->scope(); | 341 Scope* scope = info()->scope(); |
| 412 if ((scope->num_parameters() + 1) > parameter_limit) { | 342 if ((scope->num_parameters() + 1) > parameter_limit) { |
| 413 info()->set_bailout_reason(kTooManyParameters); | 343 return AbortAndDisableOptimization(kTooManyParameters); |
| 414 return AbortOptimization(); | |
| 415 } | 344 } |
| 416 | 345 |
| 417 const int locals_limit = LUnallocated::kMaxFixedSlotIndex; | 346 const int locals_limit = LUnallocated::kMaxFixedSlotIndex; |
| 418 if (info()->is_osr() && | 347 if (info()->is_osr() && |
| 419 scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) { | 348 scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) { |
| 420 info()->set_bailout_reason(kTooManyParametersLocals); | 349 return AbortAndDisableOptimization(kTooManyParametersLocals); |
| 421 return AbortOptimization(); | |
| 422 } | 350 } |
| 423 | 351 |
| 424 // Take --hydrogen-filter into account. | 352 // Take --hydrogen-filter into account. |
| 425 if (!info()->closure()->PassesFilter(FLAG_hydrogen_filter)) { | 353 if (!info()->closure()->PassesFilter(FLAG_hydrogen_filter)) { |
| 426 info()->AbortOptimization(); | 354 return AbortOptimization(kHydrogenFilter); |
| 427 return SetLastStatus(BAILED_OUT); | |
| 428 } | 355 } |
| 429 | 356 |
| 430 // Recompile the unoptimized version of the code if the current version | 357 // Recompile the unoptimized version of the code if the current version |
| 431 // doesn't have deoptimization support. Alternatively, we may decide to | 358 // doesn't have deoptimization support. Alternatively, we may decide to |
| 432 // run the full code generator to get a baseline for the compile-time | 359 // run the full code generator to get a baseline for the compile-time |
| 433 // performance of the hydrogen-based compiler. | 360 // performance of the hydrogen-based compiler. |
| 434 bool should_recompile = !info()->shared_info()->has_deoptimization_support(); | 361 bool should_recompile = !info()->shared_info()->has_deoptimization_support(); |
| 435 if (should_recompile || FLAG_hydrogen_stats) { | 362 if (should_recompile || FLAG_hydrogen_stats) { |
| 436 ElapsedTimer timer; | 363 ElapsedTimer timer; |
| 437 if (FLAG_hydrogen_stats) { | 364 if (FLAG_hydrogen_stats) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 462 // optimizations. When using the always_opt flag we disregard the | 389 // optimizations. When using the always_opt flag we disregard the |
| 463 // optimizable marker in the code object and optimize anyway. This | 390 // optimizable marker in the code object and optimize anyway. This |
| 464 // is safe as long as the unoptimized code has deoptimization | 391 // is safe as long as the unoptimized code has deoptimization |
| 465 // support. | 392 // support. |
| 466 ASSERT(FLAG_always_opt || info()->shared_info()->code()->optimizable()); | 393 ASSERT(FLAG_always_opt || info()->shared_info()->code()->optimizable()); |
| 467 ASSERT(info()->shared_info()->has_deoptimization_support()); | 394 ASSERT(info()->shared_info()->has_deoptimization_support()); |
| 468 | 395 |
| 469 if (FLAG_trace_hydrogen) { | 396 if (FLAG_trace_hydrogen) { |
| 470 Handle<String> name = info()->function()->debug_name(); | 397 Handle<String> name = info()->function()->debug_name(); |
| 471 PrintF("-----------------------------------------------------------\n"); | 398 PrintF("-----------------------------------------------------------\n"); |
| 472 PrintF("Compiling method %s using hydrogen\n", *name->ToCString()); | 399 PrintF("Compiling method %s using hydrogen\n", name->ToCString().get()); |
| 473 isolate()->GetHTracer()->TraceCompilation(info()); | 400 isolate()->GetHTracer()->TraceCompilation(info()); |
| 474 } | 401 } |
| 475 | 402 |
| 476 // Type-check the function. | 403 // Type-check the function. |
| 477 AstTyper::Run(info()); | 404 AstTyper::Run(info()); |
| 478 | 405 |
| 479 graph_builder_ = FLAG_emit_opt_code_positions | 406 graph_builder_ = FLAG_emit_opt_code_positions |
| 480 ? new(info()->zone()) HOptimizedGraphBuilderWithPositions(info()) | 407 ? new(info()->zone()) HOptimizedGraphBuilderWithPositions(info()) |
| 481 : new(info()->zone()) HOptimizedGraphBuilder(info()); | 408 : new(info()->zone()) HOptimizedGraphBuilder(info()); |
| 482 | 409 |
| 483 Timer t(this, &time_taken_to_create_graph_); | 410 Timer t(this, &time_taken_to_create_graph_); |
| 484 graph_ = graph_builder_->CreateGraph(); | 411 graph_ = graph_builder_->CreateGraph(); |
| 485 | 412 |
| 486 if (isolate()->has_pending_exception()) { | 413 if (isolate()->has_pending_exception()) { |
| 487 info()->SetCode(Handle<Code>::null()); | |
| 488 return SetLastStatus(FAILED); | 414 return SetLastStatus(FAILED); |
| 489 } | 415 } |
| 490 | 416 |
| 491 // The function being compiled may have bailed out due to an inline | 417 // The function being compiled may have bailed out due to an inline |
| 492 // candidate bailing out. In such a case, we don't disable | 418 // candidate bailing out. In such a case, we don't disable |
| 493 // optimization on the shared_info. | 419 // optimization on the shared_info. |
| 494 ASSERT(!graph_builder_->inline_bailout() || graph_ == NULL); | 420 ASSERT(!graph_builder_->inline_bailout() || graph_ == NULL); |
| 495 if (graph_ == NULL) { | 421 if (graph_ == NULL) { |
| 496 if (graph_builder_->inline_bailout()) { | 422 if (graph_builder_->inline_bailout()) { |
| 497 info_->AbortOptimization(); | 423 return AbortOptimization(); |
| 498 return SetLastStatus(BAILED_OUT); | |
| 499 } else { | 424 } else { |
| 500 return AbortOptimization(); | 425 return AbortAndDisableOptimization(); |
| 501 } | 426 } |
| 502 } | 427 } |
| 503 | 428 |
| 504 if (info()->HasAbortedDueToDependencyChange()) { | 429 if (info()->HasAbortedDueToDependencyChange()) { |
| 505 info_->set_bailout_reason(kBailedOutDueToDependencyChange); | 430 return AbortOptimization(kBailedOutDueToDependencyChange); |
| 506 info_->AbortOptimization(); | |
| 507 return SetLastStatus(BAILED_OUT); | |
| 508 } | 431 } |
| 509 | 432 |
| 510 return SetLastStatus(SUCCEEDED); | 433 return SetLastStatus(SUCCEEDED); |
| 511 } | 434 } |
| 512 | 435 |
| 513 | 436 |
| 514 RecompileJob::Status RecompileJob::OptimizeGraph() { | 437 OptimizedCompileJob::Status OptimizedCompileJob::OptimizeGraph() { |
| 515 DisallowHeapAllocation no_allocation; | 438 DisallowHeapAllocation no_allocation; |
| 516 DisallowHandleAllocation no_handles; | 439 DisallowHandleAllocation no_handles; |
| 517 DisallowHandleDereference no_deref; | 440 DisallowHandleDereference no_deref; |
| 518 DisallowCodeDependencyChange no_dependency_change; | 441 DisallowCodeDependencyChange no_dependency_change; |
| 519 | 442 |
| 520 ASSERT(last_status() == SUCCEEDED); | 443 ASSERT(last_status() == SUCCEEDED); |
| 521 Timer t(this, &time_taken_to_optimize_); | 444 Timer t(this, &time_taken_to_optimize_); |
| 522 ASSERT(graph_ != NULL); | 445 ASSERT(graph_ != NULL); |
| 523 BailoutReason bailout_reason = kNoReason; | 446 BailoutReason bailout_reason = kNoReason; |
| 524 if (!graph_->Optimize(&bailout_reason)) { | 447 |
| 525 if (bailout_reason != kNoReason) graph_builder_->Bailout(bailout_reason); | 448 if (graph_->Optimize(&bailout_reason)) { |
| 526 return SetLastStatus(BAILED_OUT); | |
| 527 } else { | |
| 528 chunk_ = LChunk::NewChunk(graph_); | 449 chunk_ = LChunk::NewChunk(graph_); |
| 529 if (chunk_ == NULL) { | 450 if (chunk_ != NULL) return SetLastStatus(SUCCEEDED); |
| 530 return SetLastStatus(BAILED_OUT); | 451 } else if (bailout_reason != kNoReason) { |
| 531 } | 452 graph_builder_->Bailout(bailout_reason); |
| 532 } | 453 } |
| 533 return SetLastStatus(SUCCEEDED); | 454 |
| 455 return AbortOptimization(); |
| 534 } | 456 } |
| 535 | 457 |
| 536 | 458 |
| 537 RecompileJob::Status RecompileJob::GenerateAndInstallCode() { | 459 OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() { |
| 538 ASSERT(last_status() == SUCCEEDED); | 460 ASSERT(last_status() == SUCCEEDED); |
| 539 ASSERT(!info()->HasAbortedDueToDependencyChange()); | 461 ASSERT(!info()->HasAbortedDueToDependencyChange()); |
| 540 DisallowCodeDependencyChange no_dependency_change; | 462 DisallowCodeDependencyChange no_dependency_change; |
| 541 { // Scope for timer. | 463 { // Scope for timer. |
| 542 Timer timer(this, &time_taken_to_codegen_); | 464 Timer timer(this, &time_taken_to_codegen_); |
| 543 ASSERT(chunk_ != NULL); | 465 ASSERT(chunk_ != NULL); |
| 544 ASSERT(graph_ != NULL); | 466 ASSERT(graph_ != NULL); |
| 545 // Deferred handles reference objects that were accessible during | 467 // Deferred handles reference objects that were accessible during |
| 546 // graph creation. To make sure that we don't encounter inconsistencies | 468 // graph creation. To make sure that we don't encounter inconsistencies |
| 547 // between graph creation and code generation, we disallow accessing | 469 // between graph creation and code generation, we disallow accessing |
| 548 // objects through deferred handles during the latter, with exceptions. | 470 // objects through deferred handles during the latter, with exceptions. |
| 549 DisallowDeferredHandleDereference no_deferred_handle_deref; | 471 DisallowDeferredHandleDereference no_deferred_handle_deref; |
| 550 Handle<Code> optimized_code = chunk_->Codegen(); | 472 Handle<Code> optimized_code = chunk_->Codegen(); |
| 551 if (optimized_code.is_null()) { | 473 if (optimized_code.is_null()) { |
| 552 if (info()->bailout_reason() == kNoReason) { | 474 if (info()->bailout_reason() == kNoReason) { |
| 553 info()->set_bailout_reason(kCodeGenerationFailed); | 475 info_->set_bailout_reason(kCodeGenerationFailed); |
| 554 } | 476 } |
| 555 return AbortOptimization(); | 477 return AbortAndDisableOptimization(); |
| 556 } | 478 } |
| 557 info()->SetCode(optimized_code); | 479 info()->SetCode(optimized_code); |
| 558 } | 480 } |
| 559 RecordOptimizationStats(); | 481 RecordOptimizationStats(); |
| 560 // Add to the weak list of optimized code objects. | 482 // Add to the weak list of optimized code objects. |
| 561 info()->context()->native_context()->AddOptimizedCode(*info()->code()); | 483 info()->context()->native_context()->AddOptimizedCode(*info()->code()); |
| 562 return SetLastStatus(SUCCEEDED); | 484 return SetLastStatus(SUCCEEDED); |
| 563 } | 485 } |
| 564 | 486 |
| 565 | 487 |
| 566 static bool GenerateCode(CompilationInfo* info) { | 488 void OptimizedCompileJob::RecordOptimizationStats() { |
| 567 bool is_optimizing = info->isolate()->use_crankshaft() && | 489 Handle<JSFunction> function = info()->closure(); |
| 568 !info->IsCompilingForDebugging() && | 490 if (!function->IsOptimized()) { |
| 569 info->IsOptimizing(); | 491 // Concurrent recompilation and OSR may race. Increment only once. |
| 570 if (is_optimizing) { | 492 int opt_count = function->shared()->opt_count(); |
| 571 Logger::TimerEventScope timer( | 493 function->shared()->set_opt_count(opt_count + 1); |
| 572 info->isolate(), Logger::TimerEventScope::v8_recompile_synchronous); | 494 } |
| 573 return MakeCrankshaftCode(info); | 495 double ms_creategraph = time_taken_to_create_graph_.InMillisecondsF(); |
| 574 } else { | 496 double ms_optimize = time_taken_to_optimize_.InMillisecondsF(); |
| 575 if (info->IsOptimizing()) { | 497 double ms_codegen = time_taken_to_codegen_.InMillisecondsF(); |
| 576 // Have the CompilationInfo decide if the compilation should be | 498 if (FLAG_trace_opt) { |
| 577 // BASE or NONOPT. | 499 PrintF("[optimizing "); |
| 578 info->DisableOptimization(); | 500 function->ShortPrint(); |
| 579 } | 501 PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize, |
| 580 Logger::TimerEventScope timer( | 502 ms_codegen); |
| 581 info->isolate(), Logger::TimerEventScope::v8_compile_full_code); | 503 } |
| 582 return FullCodeGenerator::MakeCode(info); | 504 if (FLAG_trace_opt_stats) { |
| 505 static double compilation_time = 0.0; |
| 506 static int compiled_functions = 0; |
| 507 static int code_size = 0; |
| 508 |
| 509 compilation_time += (ms_creategraph + ms_optimize + ms_codegen); |
| 510 compiled_functions++; |
| 511 code_size += function->shared()->SourceSize(); |
| 512 PrintF("Compiled: %d functions with %d byte source size in %fms.\n", |
| 513 compiled_functions, |
| 514 code_size, |
| 515 compilation_time); |
| 516 } |
| 517 if (FLAG_hydrogen_stats) { |
| 518 isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_create_graph_, |
| 519 time_taken_to_optimize_, |
| 520 time_taken_to_codegen_); |
| 583 } | 521 } |
| 584 } | 522 } |
| 585 | 523 |
| 586 | 524 |
| 587 static bool MakeCode(CompilationInfo* info) { | |
| 588 // Precondition: code has been parsed. Postcondition: the code field in | |
| 589 // the compilation info is set if compilation succeeded. | |
| 590 ASSERT(info->function() != NULL); | |
| 591 return Rewriter::Rewrite(info) && Scope::Analyze(info) && GenerateCode(info); | |
| 592 } | |
| 593 | |
| 594 | |
| 595 #ifdef ENABLE_DEBUGGER_SUPPORT | |
| 596 bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) { | |
| 597 // Precondition: code has been parsed. Postcondition: the code field in | |
| 598 // the compilation info is set if compilation succeeded. | |
| 599 bool succeeded = MakeCode(info); | |
| 600 if (!info->shared_info().is_null()) { | |
| 601 Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(), | |
| 602 info->zone()); | |
| 603 info->shared_info()->set_scope_info(*scope_info); | |
| 604 } | |
| 605 return succeeded; | |
| 606 } | |
| 607 #endif | |
| 608 | |
| 609 | |
| 610 static bool DebuggerWantsEagerCompilation(CompilationInfo* info, | |
| 611 bool allow_lazy_without_ctx = false) { | |
| 612 return LiveEditFunctionTracker::IsActive(info->isolate()) || | |
| 613 (info->isolate()->DebuggerHasBreakPoints() && !allow_lazy_without_ctx); | |
| 614 } | |
| 615 | |
| 616 | |
| 617 // Sets the expected number of properties based on estimate from compiler. | 525 // Sets the expected number of properties based on estimate from compiler. |
| 618 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared, | 526 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared, |
| 619 int estimate) { | 527 int estimate) { |
| 620 // See the comment in SetExpectedNofProperties. | 528 // See the comment in SetExpectedNofProperties. |
| 621 if (shared->live_objects_may_exist()) return; | 529 if (shared->live_objects_may_exist()) return; |
| 622 | 530 |
| 623 // If no properties are added in the constructor, they are more likely | 531 // If no properties are added in the constructor, they are more likely |
| 624 // to be added later. | 532 // to be added later. |
| 625 if (estimate == 0) estimate = 2; | 533 if (estimate == 0) estimate = 2; |
| 626 | 534 |
| 627 // TODO(yangguo): check whether those heuristics are still up-to-date. | 535 // TODO(yangguo): check whether those heuristics are still up-to-date. |
| 628 // We do not shrink objects that go into a snapshot (yet), so we adjust | 536 // We do not shrink objects that go into a snapshot (yet), so we adjust |
| 629 // the estimate conservatively. | 537 // the estimate conservatively. |
| 630 if (Serializer::enabled()) { | 538 if (Serializer::enabled()) { |
| 631 estimate += 2; | 539 estimate += 2; |
| 632 } else if (FLAG_clever_optimizations) { | 540 } else if (FLAG_clever_optimizations) { |
| 633 // Inobject slack tracking will reclaim redundant inobject space later, | 541 // Inobject slack tracking will reclaim redundant inobject space later, |
| 634 // so we can afford to adjust the estimate generously. | 542 // so we can afford to adjust the estimate generously. |
| 635 estimate += 8; | 543 estimate += 8; |
| 636 } else { | 544 } else { |
| 637 estimate += 3; | 545 estimate += 3; |
| 638 } | 546 } |
| 639 | 547 |
| 640 shared->set_expected_nof_properties(estimate); | 548 shared->set_expected_nof_properties(estimate); |
| 641 } | 549 } |
| 642 | 550 |
| 643 | 551 |
| 644 static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { | 552 static void UpdateSharedFunctionInfo(CompilationInfo* info) { |
| 553 // Update the shared function info with the compiled code and the |
| 554 // scope info. Please note, that the order of the shared function |
| 555 // info initialization is important since set_scope_info might |
| 556 // trigger a GC, causing the ASSERT below to be invalid if the code |
| 557 // was flushed. By setting the code object last we avoid this. |
| 558 Handle<SharedFunctionInfo> shared = info->shared_info(); |
| 559 Handle<ScopeInfo> scope_info = |
| 560 ScopeInfo::Create(info->scope(), info->zone()); |
| 561 shared->set_scope_info(*scope_info); |
| 562 |
| 563 Handle<Code> code = info->code(); |
| 564 CHECK(code->kind() == Code::FUNCTION); |
| 565 shared->ReplaceCode(*code); |
| 566 if (shared->optimization_disabled()) code->set_optimizable(false); |
| 567 |
| 568 // Set the expected number of properties for instances. |
| 569 FunctionLiteral* lit = info->function(); |
| 570 int expected = lit->expected_property_count(); |
| 571 SetExpectedNofPropertiesFromEstimate(shared, expected); |
| 572 |
| 573 // Check the function has compiled code. |
| 574 ASSERT(shared->is_compiled()); |
| 575 shared->set_dont_optimize_reason(lit->dont_optimize_reason()); |
| 576 shared->set_dont_inline(lit->flags()->Contains(kDontInline)); |
| 577 shared->set_ast_node_count(lit->ast_node_count()); |
| 578 shared->set_language_mode(lit->language_mode()); |
| 579 } |
| 580 |
| 581 |
| 582 // Sets the function info on a function. |
| 583 // The start_position points to the first '(' character after the function name |
| 584 // in the full script source. When counting characters in the script source the |
| 585 // the first character is number 0 (not 1). |
| 586 static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info, |
| 587 FunctionLiteral* lit, |
| 588 bool is_toplevel, |
| 589 Handle<Script> script) { |
| 590 function_info->set_length(lit->parameter_count()); |
| 591 function_info->set_formal_parameter_count(lit->parameter_count()); |
| 592 function_info->set_script(*script); |
| 593 function_info->set_function_token_position(lit->function_token_position()); |
| 594 function_info->set_start_position(lit->start_position()); |
| 595 function_info->set_end_position(lit->end_position()); |
| 596 function_info->set_is_expression(lit->is_expression()); |
| 597 function_info->set_is_anonymous(lit->is_anonymous()); |
| 598 function_info->set_is_toplevel(is_toplevel); |
| 599 function_info->set_inferred_name(*lit->inferred_name()); |
| 600 function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); |
| 601 function_info->set_allows_lazy_compilation_without_context( |
| 602 lit->AllowsLazyCompilationWithoutContext()); |
| 603 function_info->set_language_mode(lit->language_mode()); |
| 604 function_info->set_uses_arguments(lit->scope()->arguments() != NULL); |
| 605 function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); |
| 606 function_info->set_ast_node_count(lit->ast_node_count()); |
| 607 function_info->set_is_function(lit->is_function()); |
| 608 function_info->set_dont_optimize_reason(lit->dont_optimize_reason()); |
| 609 function_info->set_dont_inline(lit->flags()->Contains(kDontInline)); |
| 610 function_info->set_dont_cache(lit->flags()->Contains(kDontCache)); |
| 611 function_info->set_is_generator(lit->is_generator()); |
| 612 } |
| 613 |
| 614 |
| 615 static bool CompileUnoptimizedCode(CompilationInfo* info) { |
| 616 ASSERT(info->function() != NULL); |
| 617 if (!Rewriter::Rewrite(info)) return false; |
| 618 if (!Scope::Analyze(info)) return false; |
| 619 ASSERT(info->scope() != NULL); |
| 620 |
| 621 if (!FullCodeGenerator::MakeCode(info)) { |
| 622 Isolate* isolate = info->isolate(); |
| 623 if (!isolate->has_pending_exception()) isolate->StackOverflow(); |
| 624 return false; |
| 625 } |
| 626 return true; |
| 627 } |
| 628 |
| 629 |
| 630 static Handle<Code> GetUnoptimizedCodeCommon(CompilationInfo* info) { |
| 631 VMState<COMPILER> state(info->isolate()); |
| 632 PostponeInterruptsScope postpone(info->isolate()); |
| 633 if (!Parser::Parse(info)) return Handle<Code>::null(); |
| 634 LanguageMode language_mode = info->function()->language_mode(); |
| 635 info->SetLanguageMode(language_mode); |
| 636 |
| 637 if (!CompileUnoptimizedCode(info)) return Handle<Code>::null(); |
| 638 Compiler::RecordFunctionCompilation( |
| 639 Logger::LAZY_COMPILE_TAG, info, info->shared_info()); |
| 640 UpdateSharedFunctionInfo(info); |
| 641 ASSERT_EQ(Code::FUNCTION, info->code()->kind()); |
| 642 return info->code(); |
| 643 } |
| 644 |
| 645 |
| 646 Handle<Code> Compiler::GetUnoptimizedCode(Handle<JSFunction> function) { |
| 647 ASSERT(!function->GetIsolate()->has_pending_exception()); |
| 648 ASSERT(!function->is_compiled()); |
| 649 if (function->shared()->is_compiled()) { |
| 650 return Handle<Code>(function->shared()->code()); |
| 651 } |
| 652 |
| 653 CompilationInfoWithZone info(function); |
| 654 Handle<Code> result = GetUnoptimizedCodeCommon(&info); |
| 655 ASSERT_EQ(result.is_null(), info.isolate()->has_pending_exception()); |
| 656 |
| 657 if (FLAG_always_opt && |
| 658 !result.is_null() && |
| 659 info.isolate()->use_crankshaft() && |
| 660 !info.shared_info()->optimization_disabled() && |
| 661 !info.isolate()->DebuggerHasBreakPoints()) { |
| 662 Handle<Code> opt_code = Compiler::GetOptimizedCode( |
| 663 function, result, Compiler::NOT_CONCURRENT); |
| 664 if (!opt_code.is_null()) result = opt_code; |
| 665 } |
| 666 |
| 667 return result; |
| 668 } |
| 669 |
| 670 |
| 671 Handle<Code> Compiler::GetUnoptimizedCode(Handle<SharedFunctionInfo> shared) { |
| 672 ASSERT(!shared->GetIsolate()->has_pending_exception()); |
| 673 ASSERT(!shared->is_compiled()); |
| 674 |
| 675 CompilationInfoWithZone info(shared); |
| 676 Handle<Code> result = GetUnoptimizedCodeCommon(&info); |
| 677 ASSERT_EQ(result.is_null(), info.isolate()->has_pending_exception()); |
| 678 return result; |
| 679 } |
| 680 |
| 681 |
| 682 bool Compiler::EnsureCompiled(Handle<JSFunction> function, |
| 683 ClearExceptionFlag flag) { |
| 684 if (function->is_compiled()) return true; |
| 685 Handle<Code> code = Compiler::GetUnoptimizedCode(function); |
| 686 if (code.is_null()) { |
| 687 if (flag == CLEAR_EXCEPTION) { |
| 688 function->GetIsolate()->clear_pending_exception(); |
| 689 } |
| 690 return false; |
| 691 } |
| 692 function->ReplaceCode(*code); |
| 693 ASSERT(function->is_compiled()); |
| 694 return true; |
| 695 } |
| 696 |
| 697 |
| 698 // Compile full code for debugging. This code will have debug break slots |
| 699 // and deoptimization information. Deoptimization information is required |
| 700 // in case that an optimized version of this function is still activated on |
| 701 // the stack. It will also make sure that the full code is compiled with |
| 702 // the same flags as the previous version, that is flags which can change |
| 703 // the code generated. The current method of mapping from already compiled |
| 704 // full code without debug break slots to full code with debug break slots |
| 705 // depends on the generated code is otherwise exactly the same. |
| 706 // If compilation fails, just keep the existing code. |
| 707 Handle<Code> Compiler::GetCodeForDebugging(Handle<JSFunction> function) { |
| 708 CompilationInfoWithZone info(function); |
| 709 Isolate* isolate = info.isolate(); |
| 710 VMState<COMPILER> state(isolate); |
| 711 |
| 712 ASSERT(!isolate->has_pending_exception()); |
| 713 Handle<Code> old_code(function->shared()->code()); |
| 714 ASSERT(old_code->kind() == Code::FUNCTION); |
| 715 ASSERT(!old_code->has_debug_break_slots()); |
| 716 |
| 717 info.MarkCompilingForDebugging(); |
| 718 if (old_code->is_compiled_optimizable()) { |
| 719 info.EnableDeoptimizationSupport(); |
| 720 } else { |
| 721 info.MarkNonOptimizable(); |
| 722 } |
| 723 Handle<Code> new_code = GetUnoptimizedCodeCommon(&info); |
| 724 if (new_code.is_null()) { |
| 725 isolate->clear_pending_exception(); |
| 726 } else { |
| 727 ASSERT_EQ(old_code->is_compiled_optimizable(), |
| 728 new_code->is_compiled_optimizable()); |
| 729 } |
| 730 return new_code; |
| 731 } |
| 732 |
| 733 |
| 734 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 735 void Compiler::CompileForLiveEdit(Handle<Script> script) { |
| 736 // TODO(635): support extensions. |
| 737 CompilationInfoWithZone info(script); |
| 738 PostponeInterruptsScope postpone(info.isolate()); |
| 739 VMState<COMPILER> state(info.isolate()); |
| 740 |
| 741 info.MarkAsGlobal(); |
| 742 if (!Parser::Parse(&info)) return; |
| 743 LanguageMode language_mode = info.function()->language_mode(); |
| 744 info.SetLanguageMode(language_mode); |
| 745 |
| 746 LiveEditFunctionTracker tracker(info.isolate(), info.function()); |
| 747 if (!CompileUnoptimizedCode(&info)) return; |
| 748 if (!info.shared_info().is_null()) { |
| 749 Handle<ScopeInfo> scope_info = ScopeInfo::Create(info.scope(), |
| 750 info.zone()); |
| 751 info.shared_info()->set_scope_info(*scope_info); |
| 752 } |
| 753 tracker.RecordRootFunctionInfo(info.code()); |
| 754 } |
| 755 #endif |
| 756 |
| 757 |
| 758 static bool DebuggerWantsEagerCompilation(CompilationInfo* info, |
| 759 bool allow_lazy_without_ctx = false) { |
| 760 return LiveEditFunctionTracker::IsActive(info->isolate()) || |
| 761 (info->isolate()->DebuggerHasBreakPoints() && !allow_lazy_without_ctx); |
| 762 } |
| 763 |
| 764 |
| 765 static Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { |
| 645 Isolate* isolate = info->isolate(); | 766 Isolate* isolate = info->isolate(); |
| 646 PostponeInterruptsScope postpone(isolate); | 767 PostponeInterruptsScope postpone(isolate); |
| 647 | |
| 648 ASSERT(!isolate->native_context().is_null()); | 768 ASSERT(!isolate->native_context().is_null()); |
| 649 Handle<Script> script = info->script(); | 769 Handle<Script> script = info->script(); |
| 770 |
| 650 // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile? | 771 // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile? |
| 651 FixedArray* array = isolate->native_context()->embedder_data(); | 772 FixedArray* array = isolate->native_context()->embedder_data(); |
| 652 script->set_context_data(array->get(0)); | 773 script->set_context_data(array->get(0)); |
| 653 | 774 |
| 654 #ifdef ENABLE_DEBUGGER_SUPPORT | 775 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 655 if (info->is_eval()) { | |
| 656 script->set_compilation_type(Script::COMPILATION_TYPE_EVAL); | |
| 657 // For eval scripts add information on the function from which eval was | |
| 658 // called. | |
| 659 if (info->is_eval()) { | |
| 660 StackTraceFrameIterator it(isolate); | |
| 661 if (!it.done()) { | |
| 662 script->set_eval_from_shared(it.frame()->function()->shared()); | |
| 663 Code* code = it.frame()->LookupCode(); | |
| 664 int offset = static_cast<int>( | |
| 665 it.frame()->pc() - code->instruction_start()); | |
| 666 script->set_eval_from_instructions_offset(Smi::FromInt(offset)); | |
| 667 } | |
| 668 } | |
| 669 } | |
| 670 | |
| 671 // Notify debugger | |
| 672 isolate->debugger()->OnBeforeCompile(script); | 776 isolate->debugger()->OnBeforeCompile(script); |
| 673 #endif | 777 #endif |
| 674 | 778 |
| 675 // Only allow non-global compiles for eval. | |
| 676 ASSERT(info->is_eval() || info->is_global()); | 779 ASSERT(info->is_eval() || info->is_global()); |
| 677 { | 780 |
| 678 Parser parser(info); | 781 bool parse_allow_lazy = |
| 679 if ((info->pre_parse_data() != NULL || | 782 (info->pre_parse_data() != NULL || |
| 680 String::cast(script->source())->length() > FLAG_min_preparse_length) && | 783 String::cast(script->source())->length() > FLAG_min_preparse_length) && |
| 681 !DebuggerWantsEagerCompilation(info)) | 784 !DebuggerWantsEagerCompilation(info); |
| 682 parser.set_allow_lazy(true); | 785 |
| 683 if (!parser.Parse()) { | 786 Handle<SharedFunctionInfo> result; |
| 787 |
| 788 { VMState<COMPILER> state(info->isolate()); |
| 789 if (!Parser::Parse(info, parse_allow_lazy)) { |
| 684 return Handle<SharedFunctionInfo>::null(); | 790 return Handle<SharedFunctionInfo>::null(); |
| 685 } | 791 } |
| 686 } | 792 |
| 687 | 793 FunctionLiteral* lit = info->function(); |
| 688 FunctionLiteral* lit = info->function(); | 794 LiveEditFunctionTracker live_edit_tracker(isolate, lit); |
| 689 LiveEditFunctionTracker live_edit_tracker(isolate, lit); | 795 |
| 690 Handle<SharedFunctionInfo> result; | |
| 691 { | |
| 692 // Measure how long it takes to do the compilation; only take the | 796 // Measure how long it takes to do the compilation; only take the |
| 693 // rest of the function into account to avoid overlap with the | 797 // rest of the function into account to avoid overlap with the |
| 694 // parsing statistics. | 798 // parsing statistics. |
| 695 HistogramTimer* rate = info->is_eval() | 799 HistogramTimer* rate = info->is_eval() |
| 696 ? info->isolate()->counters()->compile_eval() | 800 ? info->isolate()->counters()->compile_eval() |
| 697 : info->isolate()->counters()->compile(); | 801 : info->isolate()->counters()->compile(); |
| 698 HistogramTimerScope timer(rate); | 802 HistogramTimerScope timer(rate); |
| 699 | 803 |
| 700 // Compile the code. | 804 // Compile the code. |
| 701 if (!MakeCode(info)) { | 805 if (!CompileUnoptimizedCode(info)) { |
| 702 if (!isolate->has_pending_exception()) isolate->StackOverflow(); | |
| 703 return Handle<SharedFunctionInfo>::null(); | 806 return Handle<SharedFunctionInfo>::null(); |
| 704 } | 807 } |
| 705 | 808 |
| 706 // Allocate function. | 809 // Allocate function. |
| 707 ASSERT(!info->code().is_null()); | 810 ASSERT(!info->code().is_null()); |
| 708 result = | 811 result = isolate->factory()->NewSharedFunctionInfo( |
| 709 isolate->factory()->NewSharedFunctionInfo( | 812 lit->name(), |
| 710 lit->name(), | 813 lit->materialized_literal_count(), |
| 711 lit->materialized_literal_count(), | 814 lit->is_generator(), |
| 712 lit->is_generator(), | 815 info->code(), |
| 713 info->code(), | 816 ScopeInfo::Create(info->scope(), info->zone())); |
| 714 ScopeInfo::Create(info->scope(), info->zone())); | |
| 715 | 817 |
| 716 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); | 818 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); |
| 717 Compiler::SetFunctionInfo(result, lit, true, script); | 819 SetFunctionInfo(result, lit, true, script); |
| 718 | 820 |
| 719 if (script->name()->IsString()) { | 821 Handle<String> script_name = script->name()->IsString() |
| 720 PROFILE(isolate, CodeCreateEvent( | 822 ? Handle<String>(String::cast(script->name())) |
| 721 info->is_eval() | 823 : isolate->factory()->empty_string(); |
| 722 ? Logger::EVAL_TAG | 824 Logger::LogEventsAndTags log_tag = info->is_eval() |
| 723 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), | 825 ? Logger::EVAL_TAG |
| 724 *info->code(), | 826 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script); |
| 725 *result, | 827 |
| 726 info, | 828 PROFILE(isolate, CodeCreateEvent( |
| 727 String::cast(script->name()))); | 829 log_tag, *info->code(), *result, info, *script_name)); |
| 728 GDBJIT(AddCode(Handle<String>(String::cast(script->name())), | 830 GDBJIT(AddCode(script_name, script, info->code(), info)); |
| 729 script, | |
| 730 info->code(), | |
| 731 info)); | |
| 732 } else { | |
| 733 PROFILE(isolate, CodeCreateEvent( | |
| 734 info->is_eval() | |
| 735 ? Logger::EVAL_TAG | |
| 736 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), | |
| 737 *info->code(), | |
| 738 *result, | |
| 739 info, | |
| 740 isolate->heap()->empty_string())); | |
| 741 GDBJIT(AddCode(Handle<String>(), script, info->code(), info)); | |
| 742 } | |
| 743 | 831 |
| 744 // Hint to the runtime system used when allocating space for initial | 832 // Hint to the runtime system used when allocating space for initial |
| 745 // property space by setting the expected number of properties for | 833 // property space by setting the expected number of properties for |
| 746 // the instances of the function. | 834 // the instances of the function. |
| 747 SetExpectedNofPropertiesFromEstimate(result, | 835 SetExpectedNofPropertiesFromEstimate(result, |
| 748 lit->expected_property_count()); | 836 lit->expected_property_count()); |
| 749 | 837 |
| 750 script->set_compilation_state(Script::COMPILATION_STATE_COMPILED); | 838 script->set_compilation_state(Script::COMPILATION_STATE_COMPILED); |
| 839 |
| 840 live_edit_tracker.RecordFunctionInfo(result, lit, info->zone()); |
| 751 } | 841 } |
| 752 | 842 |
| 753 #ifdef ENABLE_DEBUGGER_SUPPORT | 843 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 754 // Notify debugger | 844 isolate->debugger()->OnAfterCompile(script, Debugger::NO_AFTER_COMPILE_FLAGS); |
| 755 isolate->debugger()->OnAfterCompile( | |
| 756 script, Debugger::NO_AFTER_COMPILE_FLAGS); | |
| 757 #endif | 845 #endif |
| 758 | 846 |
| 759 live_edit_tracker.RecordFunctionInfo(result, lit, info->zone()); | |
| 760 | |
| 761 return result; | 847 return result; |
| 762 } | 848 } |
| 763 | 849 |
| 764 | 850 |
| 765 Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, | 851 Handle<JSFunction> Compiler::GetFunctionFromEval(Handle<String> source, |
| 766 Handle<Object> script_name, | 852 Handle<Context> context, |
| 767 int line_offset, | 853 LanguageMode language_mode, |
| 768 int column_offset, | 854 ParseRestriction restriction, |
| 769 bool is_shared_cross_origin, | 855 int scope_position) { |
| 770 Handle<Context> context, | 856 Isolate* isolate = source->GetIsolate(); |
| 771 v8::Extension* extension, | 857 int source_length = source->length(); |
| 772 ScriptDataImpl* pre_data, | 858 isolate->counters()->total_eval_size()->Increment(source_length); |
| 773 Handle<Object> script_data, | 859 isolate->counters()->total_compile_size()->Increment(source_length); |
| 774 NativesFlag natives) { | 860 |
| 861 CompilationCache* compilation_cache = isolate->compilation_cache(); |
| 862 Handle<SharedFunctionInfo> shared_info = compilation_cache->LookupEval( |
| 863 source, context, language_mode, scope_position); |
| 864 |
| 865 if (shared_info.is_null()) { |
| 866 Handle<Script> script = isolate->factory()->NewScript(source); |
| 867 CompilationInfoWithZone info(script); |
| 868 info.MarkAsEval(); |
| 869 if (context->IsNativeContext()) info.MarkAsGlobal(); |
| 870 info.SetLanguageMode(language_mode); |
| 871 info.SetParseRestriction(restriction); |
| 872 info.SetContext(context); |
| 873 |
| 874 #if ENABLE_DEBUGGER_SUPPORT |
| 875 Debug::RecordEvalCaller(script); |
| 876 #endif // ENABLE_DEBUGGER_SUPPORT |
| 877 |
| 878 shared_info = CompileToplevel(&info); |
| 879 |
| 880 if (shared_info.is_null()) { |
| 881 return Handle<JSFunction>::null(); |
| 882 } else { |
| 883 // Explicitly disable optimization for eval code. We're not yet prepared |
| 884 // to handle eval-code in the optimizing compiler. |
| 885 shared_info->DisableOptimization(kEval); |
| 886 |
| 887 // If caller is strict mode, the result must be in strict mode or |
| 888 // extended mode as well, but not the other way around. Consider: |
| 889 // eval("'use strict'; ..."); |
| 890 ASSERT(language_mode != STRICT_MODE || !shared_info->is_classic_mode()); |
| 891 // If caller is in extended mode, the result must also be in |
| 892 // extended mode. |
| 893 ASSERT(language_mode != EXTENDED_MODE || |
| 894 shared_info->is_extended_mode()); |
| 895 if (!shared_info->dont_cache()) { |
| 896 compilation_cache->PutEval( |
| 897 source, context, shared_info, scope_position); |
| 898 } |
| 899 } |
| 900 } else if (shared_info->ic_age() != isolate->heap()->global_ic_age()) { |
| 901 shared_info->ResetForNewContext(isolate->heap()->global_ic_age()); |
| 902 } |
| 903 |
| 904 return isolate->factory()->NewFunctionFromSharedFunctionInfo( |
| 905 shared_info, context, NOT_TENURED); |
| 906 } |
| 907 |
| 908 |
| 909 Handle<SharedFunctionInfo> Compiler::CompileScript(Handle<String> source, |
| 910 Handle<Object> script_name, |
| 911 int line_offset, |
| 912 int column_offset, |
| 913 bool is_shared_cross_origin, |
| 914 Handle<Context> context, |
| 915 v8::Extension* extension, |
| 916 ScriptDataImpl* pre_data, |
| 917 Handle<Object> script_data, |
| 918 NativesFlag natives) { |
| 775 Isolate* isolate = source->GetIsolate(); | 919 Isolate* isolate = source->GetIsolate(); |
| 776 int source_length = source->length(); | 920 int source_length = source->length(); |
| 777 isolate->counters()->total_load_size()->Increment(source_length); | 921 isolate->counters()->total_load_size()->Increment(source_length); |
| 778 isolate->counters()->total_compile_size()->Increment(source_length); | 922 isolate->counters()->total_compile_size()->Increment(source_length); |
| 779 | 923 |
| 780 // The VM is in the COMPILER state until exiting this function. | |
| 781 VMState<COMPILER> state(isolate); | |
| 782 | |
| 783 CompilationCache* compilation_cache = isolate->compilation_cache(); | 924 CompilationCache* compilation_cache = isolate->compilation_cache(); |
| 784 | 925 |
| 785 // Do a lookup in the compilation cache but not for extensions. | 926 // Do a lookup in the compilation cache but not for extensions. |
| 786 Handle<SharedFunctionInfo> result; | 927 Handle<SharedFunctionInfo> result; |
| 787 if (extension == NULL) { | 928 if (extension == NULL) { |
| 788 result = compilation_cache->LookupScript(source, | 929 result = compilation_cache->LookupScript(source, |
| 789 script_name, | 930 script_name, |
| 790 line_offset, | 931 line_offset, |
| 791 column_offset, | 932 column_offset, |
| 792 is_shared_cross_origin, | 933 is_shared_cross_origin, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 820 | 961 |
| 821 // Compile the function and add it to the cache. | 962 // Compile the function and add it to the cache. |
| 822 CompilationInfoWithZone info(script); | 963 CompilationInfoWithZone info(script); |
| 823 info.MarkAsGlobal(); | 964 info.MarkAsGlobal(); |
| 824 info.SetExtension(extension); | 965 info.SetExtension(extension); |
| 825 info.SetPreParseData(pre_data); | 966 info.SetPreParseData(pre_data); |
| 826 info.SetContext(context); | 967 info.SetContext(context); |
| 827 if (FLAG_use_strict) { | 968 if (FLAG_use_strict) { |
| 828 info.SetLanguageMode(FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE); | 969 info.SetLanguageMode(FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE); |
| 829 } | 970 } |
| 830 result = MakeFunctionInfo(&info); | 971 result = CompileToplevel(&info); |
| 831 if (extension == NULL && !result.is_null() && !result->dont_cache()) { | 972 if (extension == NULL && !result.is_null() && !result->dont_cache()) { |
| 832 compilation_cache->PutScript(source, context, result); | 973 compilation_cache->PutScript(source, context, result); |
| 833 } | 974 } |
| 834 } else { | 975 } else if (result->ic_age() != isolate->heap()->global_ic_age()) { |
| 835 if (result->ic_age() != isolate->heap()->global_ic_age()) { | |
| 836 result->ResetForNewContext(isolate->heap()->global_ic_age()); | 976 result->ResetForNewContext(isolate->heap()->global_ic_age()); |
| 837 } | |
| 838 } | 977 } |
| 839 | 978 |
| 840 if (result.is_null()) isolate->ReportPendingMessages(); | 979 if (result.is_null()) isolate->ReportPendingMessages(); |
| 841 return result; | 980 return result; |
| 842 } | 981 } |
| 843 | 982 |
| 844 | 983 |
| 845 Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, | 984 Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, |
| 846 Handle<Context> context, | 985 Handle<Script> script) { |
| 847 bool is_global, | 986 // Precondition: code has been parsed and scopes have been analyzed. |
| 848 LanguageMode language_mode, | 987 CompilationInfoWithZone info(script); |
| 849 ParseRestriction restriction, | 988 info.SetFunction(literal); |
| 850 int scope_position) { | 989 info.SetScope(literal->scope()); |
| 851 Isolate* isolate = source->GetIsolate(); | 990 info.SetLanguageMode(literal->scope()->language_mode()); |
| 852 int source_length = source->length(); | |
| 853 isolate->counters()->total_eval_size()->Increment(source_length); | |
| 854 isolate->counters()->total_compile_size()->Increment(source_length); | |
| 855 | 991 |
| 856 // The VM is in the COMPILER state until exiting this function. | 992 Isolate* isolate = info.isolate(); |
| 857 VMState<COMPILER> state(isolate); | 993 Factory* factory = isolate->factory(); |
| 994 LiveEditFunctionTracker live_edit_tracker(isolate, literal); |
| 995 // Determine if the function can be lazily compiled. This is necessary to |
| 996 // allow some of our builtin JS files to be lazily compiled. These |
| 997 // builtins cannot be handled lazily by the parser, since we have to know |
| 998 // if a function uses the special natives syntax, which is something the |
| 999 // parser records. |
| 1000 // If the debugger requests compilation for break points, we cannot be |
| 1001 // aggressive about lazy compilation, because it might trigger compilation |
| 1002 // of functions without an outer context when setting a breakpoint through |
| 1003 // Debug::FindSharedFunctionInfoInScript. |
| 1004 bool allow_lazy_without_ctx = literal->AllowsLazyCompilationWithoutContext(); |
| 1005 bool allow_lazy = literal->AllowsLazyCompilation() && |
| 1006 !DebuggerWantsEagerCompilation(&info, allow_lazy_without_ctx); |
| 858 | 1007 |
| 859 // Do a lookup in the compilation cache; if the entry is not there, invoke | 1008 // Generate code |
| 860 // the compiler and add the result to the cache. | 1009 Handle<ScopeInfo> scope_info; |
| 861 Handle<SharedFunctionInfo> result; | 1010 if (FLAG_lazy && allow_lazy && !literal->is_parenthesized()) { |
| 862 CompilationCache* compilation_cache = isolate->compilation_cache(); | 1011 Handle<Code> code = isolate->builtins()->CompileUnoptimized(); |
| 863 result = compilation_cache->LookupEval(source, | 1012 info.SetCode(code); |
| 864 context, | 1013 scope_info = Handle<ScopeInfo>(ScopeInfo::Empty(isolate)); |
| 865 is_global, | 1014 } else if (FullCodeGenerator::MakeCode(&info)) { |
| 866 language_mode, | 1015 ASSERT(!info.code().is_null()); |
| 867 scope_position); | 1016 scope_info = ScopeInfo::Create(info.scope(), info.zone()); |
| 868 | |
| 869 if (result.is_null()) { | |
| 870 // Create a script object describing the script to be compiled. | |
| 871 Handle<Script> script = isolate->factory()->NewScript(source); | |
| 872 CompilationInfoWithZone info(script); | |
| 873 info.MarkAsEval(); | |
| 874 if (is_global) info.MarkAsGlobal(); | |
| 875 info.SetLanguageMode(language_mode); | |
| 876 info.SetParseRestriction(restriction); | |
| 877 info.SetContext(context); | |
| 878 result = MakeFunctionInfo(&info); | |
| 879 if (!result.is_null()) { | |
| 880 // Explicitly disable optimization for eval code. We're not yet prepared | |
| 881 // to handle eval-code in the optimizing compiler. | |
| 882 result->DisableOptimization(kEval); | |
| 883 | |
| 884 // If caller is strict mode, the result must be in strict mode or | |
| 885 // extended mode as well, but not the other way around. Consider: | |
| 886 // eval("'use strict'; ..."); | |
| 887 ASSERT(language_mode != STRICT_MODE || !result->is_classic_mode()); | |
| 888 // If caller is in extended mode, the result must also be in | |
| 889 // extended mode. | |
| 890 ASSERT(language_mode != EXTENDED_MODE || | |
| 891 result->is_extended_mode()); | |
| 892 if (!result->dont_cache()) { | |
| 893 compilation_cache->PutEval( | |
| 894 source, context, is_global, result, scope_position); | |
| 895 } | |
| 896 } | |
| 897 } else { | 1017 } else { |
| 898 if (result->ic_age() != isolate->heap()->global_ic_age()) { | 1018 return Handle<SharedFunctionInfo>::null(); |
| 899 result->ResetForNewContext(isolate->heap()->global_ic_age()); | |
| 900 } | |
| 901 } | 1019 } |
| 902 | 1020 |
| 1021 // Create a shared function info object. |
| 1022 Handle<SharedFunctionInfo> result = |
| 1023 factory->NewSharedFunctionInfo(literal->name(), |
| 1024 literal->materialized_literal_count(), |
| 1025 literal->is_generator(), |
| 1026 info.code(), |
| 1027 scope_info); |
| 1028 SetFunctionInfo(result, literal, false, script); |
| 1029 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result); |
| 1030 result->set_allows_lazy_compilation(allow_lazy); |
| 1031 result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx); |
| 1032 |
| 1033 // Set the expected number of properties for instances and return |
| 1034 // the resulting function. |
| 1035 SetExpectedNofPropertiesFromEstimate(result, |
| 1036 literal->expected_property_count()); |
| 1037 live_edit_tracker.RecordFunctionInfo(result, literal, info.zone()); |
| 903 return result; | 1038 return result; |
| 904 } | 1039 } |
| 905 | 1040 |
| 906 | 1041 |
| 907 static bool InstallFullCode(CompilationInfo* info) { | 1042 static Handle<Code> GetCodeFromOptimizedCodeMap(Handle<JSFunction> function, |
| 908 // Update the shared function info with the compiled code and the | 1043 BailoutId osr_ast_id) { |
| 909 // scope info. Please note, that the order of the shared function | 1044 if (FLAG_cache_optimized_code) { |
| 910 // info initialization is important since set_scope_info might | 1045 Handle<SharedFunctionInfo> shared(function->shared()); |
| 911 // trigger a GC, causing the ASSERT below to be invalid if the code | 1046 DisallowHeapAllocation no_gc; |
| 912 // was flushed. By setting the code object last we avoid this. | 1047 int index = shared->SearchOptimizedCodeMap( |
| 913 Handle<SharedFunctionInfo> shared = info->shared_info(); | 1048 function->context()->native_context(), osr_ast_id); |
| 914 Handle<Code> code = info->code(); | 1049 if (index > 0) { |
| 915 CHECK(code->kind() == Code::FUNCTION); | 1050 if (FLAG_trace_opt) { |
| 916 Handle<JSFunction> function = info->closure(); | 1051 PrintF("[found optimized code for "); |
| 917 Handle<ScopeInfo> scope_info = | 1052 function->ShortPrint(); |
| 918 ScopeInfo::Create(info->scope(), info->zone()); | 1053 if (!osr_ast_id.IsNone()) { |
| 919 shared->set_scope_info(*scope_info); | 1054 PrintF(" at OSR AST id %d", osr_ast_id.ToInt()); |
| 920 shared->ReplaceCode(*code); | 1055 } |
| 921 if (!function.is_null()) { | 1056 PrintF("]\n"); |
| 922 function->ReplaceCode(*code); | 1057 } |
| 923 ASSERT(!function->IsOptimized()); | 1058 FixedArray* literals = shared->GetLiteralsFromOptimizedCodeMap(index); |
| 924 } | 1059 if (literals != NULL) function->set_literals(literals); |
| 925 | 1060 return Handle<Code>(shared->GetCodeFromOptimizedCodeMap(index)); |
| 926 // Set the expected number of properties for instances. | |
| 927 FunctionLiteral* lit = info->function(); | |
| 928 int expected = lit->expected_property_count(); | |
| 929 SetExpectedNofPropertiesFromEstimate(shared, expected); | |
| 930 | |
| 931 // Check the function has compiled code. | |
| 932 ASSERT(shared->is_compiled()); | |
| 933 shared->set_dont_optimize_reason(lit->dont_optimize_reason()); | |
| 934 shared->set_dont_inline(lit->flags()->Contains(kDontInline)); | |
| 935 shared->set_ast_node_count(lit->ast_node_count()); | |
| 936 | |
| 937 if (info->isolate()->use_crankshaft() && | |
| 938 !function.is_null() && | |
| 939 !shared->optimization_disabled()) { | |
| 940 // If we're asked to always optimize, we compile the optimized | |
| 941 // version of the function right away - unless the debugger is | |
| 942 // active as it makes no sense to compile optimized code then. | |
| 943 if (FLAG_always_opt && | |
| 944 !info->isolate()->DebuggerHasBreakPoints()) { | |
| 945 CompilationInfoWithZone optimized(function); | |
| 946 optimized.SetOptimizing(BailoutId::None()); | |
| 947 return Compiler::CompileLazy(&optimized); | |
| 948 } | 1061 } |
| 949 } | 1062 } |
| 950 return true; | 1063 return Handle<Code>::null(); |
| 951 } | 1064 } |
| 952 | 1065 |
| 953 | 1066 |
| 954 static void InstallCodeCommon(CompilationInfo* info) { | |
| 955 Handle<SharedFunctionInfo> shared = info->shared_info(); | |
| 956 Handle<Code> code = info->code(); | |
| 957 ASSERT(!code.is_null()); | |
| 958 | |
| 959 // Set optimizable to false if this is disallowed by the shared | |
| 960 // function info, e.g., we might have flushed the code and must | |
| 961 // reset this bit when lazy compiling the code again. | |
| 962 if (shared->optimization_disabled()) code->set_optimizable(false); | |
| 963 | |
| 964 if (shared->code() == *code) { | |
| 965 // Do not send compilation event for the same code twice. | |
| 966 return; | |
| 967 } | |
| 968 Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared); | |
| 969 } | |
| 970 | |
| 971 | |
| 972 static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { | 1067 static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { |
| 973 Handle<Code> code = info->code(); | 1068 Handle<Code> code = info->code(); |
| 974 if (code->kind() != Code::OPTIMIZED_FUNCTION) return; // Nothing to do. | 1069 if (code->kind() != Code::OPTIMIZED_FUNCTION) return; // Nothing to do. |
| 975 | 1070 |
| 976 // Cache non-OSR optimized code. | 1071 // Cache optimized code. |
| 977 if (FLAG_cache_optimized_code && !info->is_osr()) { | 1072 if (FLAG_cache_optimized_code) { |
| 978 Handle<JSFunction> function = info->closure(); | 1073 Handle<JSFunction> function = info->closure(); |
| 979 Handle<SharedFunctionInfo> shared(function->shared()); | 1074 Handle<SharedFunctionInfo> shared(function->shared()); |
| 980 Handle<FixedArray> literals(function->literals()); | 1075 Handle<FixedArray> literals(function->literals()); |
| 981 Handle<Context> native_context(function->context()->native_context()); | 1076 Handle<Context> native_context(function->context()->native_context()); |
| 982 SharedFunctionInfo::AddToOptimizedCodeMap( | 1077 SharedFunctionInfo::AddToOptimizedCodeMap( |
| 983 shared, native_context, code, literals); | 1078 shared, native_context, code, literals, info->osr_ast_id()); |
| 984 } | 1079 } |
| 985 } | 1080 } |
| 986 | 1081 |
| 987 | 1082 |
| 988 static bool InstallCodeFromOptimizedCodeMap(CompilationInfo* info) { | 1083 static bool CompileOptimizedPrologue(CompilationInfo* info) { |
| 989 if (!info->IsOptimizing()) return false; // Nothing to look up. | 1084 if (!Parser::Parse(info)) return false; |
| 1085 LanguageMode language_mode = info->function()->language_mode(); |
| 1086 info->SetLanguageMode(language_mode); |
| 990 | 1087 |
| 991 // Lookup non-OSR optimized code. | 1088 if (!Rewriter::Rewrite(info)) return false; |
| 992 if (FLAG_cache_optimized_code && !info->is_osr()) { | 1089 if (!Scope::Analyze(info)) return false; |
| 993 Handle<SharedFunctionInfo> shared = info->shared_info(); | 1090 ASSERT(info->scope() != NULL); |
| 994 Handle<JSFunction> function = info->closure(); | 1091 return true; |
| 995 ASSERT(!function.is_null()); | |
| 996 Handle<Context> native_context(function->context()->native_context()); | |
| 997 int index = shared->SearchOptimizedCodeMap(*native_context); | |
| 998 if (index > 0) { | |
| 999 if (FLAG_trace_opt) { | |
| 1000 PrintF("[found optimized code for "); | |
| 1001 function->ShortPrint(); | |
| 1002 PrintF("]\n"); | |
| 1003 } | |
| 1004 // Caching of optimized code enabled and optimized code found. | |
| 1005 shared->InstallFromOptimizedCodeMap(*function, index); | |
| 1006 return true; | |
| 1007 } | |
| 1008 } | |
| 1009 return false; | |
| 1010 } | 1092 } |
| 1011 | 1093 |
| 1012 | 1094 |
| 1013 bool Compiler::CompileLazy(CompilationInfo* info) { | 1095 static bool GetOptimizedCodeNow(CompilationInfo* info) { |
| 1014 Isolate* isolate = info->isolate(); | 1096 if (!CompileOptimizedPrologue(info)) return false; |
| 1015 | 1097 |
| 1016 // The VM is in the COMPILER state until exiting this function. | 1098 Logger::TimerEventScope timer( |
| 1017 VMState<COMPILER> state(isolate); | 1099 info->isolate(), Logger::TimerEventScope::v8_recompile_synchronous); |
| 1018 | 1100 |
| 1019 PostponeInterruptsScope postpone(isolate); | 1101 OptimizedCompileJob job(info); |
| 1102 if (job.CreateGraph() != OptimizedCompileJob::SUCCEEDED) return false; |
| 1103 if (job.OptimizeGraph() != OptimizedCompileJob::SUCCEEDED) return false; |
| 1104 if (job.GenerateCode() != OptimizedCompileJob::SUCCEEDED) return false; |
| 1020 | 1105 |
| 1021 Handle<SharedFunctionInfo> shared = info->shared_info(); | 1106 // Success! |
| 1022 int compiled_size = shared->end_position() - shared->start_position(); | 1107 ASSERT(!info->isolate()->has_pending_exception()); |
| 1023 isolate->counters()->total_compile_size()->Increment(compiled_size); | 1108 InsertCodeIntoOptimizedCodeMap(info); |
| 1024 | 1109 Compiler::RecordFunctionCompilation( |
| 1025 if (InstallCodeFromOptimizedCodeMap(info)) return true; | 1110 Logger::LAZY_COMPILE_TAG, info, info->shared_info()); |
| 1026 | 1111 return true; |
| 1027 // Generate the AST for the lazily compiled function. | |
| 1028 if (Parser::Parse(info)) { | |
| 1029 // Measure how long it takes to do the lazy compilation; only take the | |
| 1030 // rest of the function into account to avoid overlap with the lazy | |
| 1031 // parsing statistics. | |
| 1032 HistogramTimerScope timer(isolate->counters()->compile_lazy()); | |
| 1033 | |
| 1034 // After parsing we know the function's language mode. Remember it. | |
| 1035 LanguageMode language_mode = info->function()->language_mode(); | |
| 1036 info->SetLanguageMode(language_mode); | |
| 1037 shared->set_language_mode(language_mode); | |
| 1038 | |
| 1039 // Compile the code. | |
| 1040 if (!MakeCode(info)) { | |
| 1041 if (!isolate->has_pending_exception()) { | |
| 1042 isolate->StackOverflow(); | |
| 1043 } | |
| 1044 } else { | |
| 1045 InstallCodeCommon(info); | |
| 1046 | |
| 1047 if (info->IsOptimizing()) { | |
| 1048 // Optimized code successfully created. | |
| 1049 Handle<Code> code = info->code(); | |
| 1050 ASSERT(shared->scope_info() != ScopeInfo::Empty(isolate)); | |
| 1051 // TODO(titzer): Only replace the code if it was not an OSR compile. | |
| 1052 info->closure()->ReplaceCode(*code); | |
| 1053 InsertCodeIntoOptimizedCodeMap(info); | |
| 1054 return true; | |
| 1055 } else if (!info->is_osr()) { | |
| 1056 // Compilation failed. Replace with full code if not OSR compile. | |
| 1057 return InstallFullCode(info); | |
| 1058 } | |
| 1059 } | |
| 1060 } | |
| 1061 | |
| 1062 ASSERT(info->code().is_null()); | |
| 1063 return false; | |
| 1064 } | 1112 } |
| 1065 | 1113 |
| 1066 | 1114 |
| 1067 bool Compiler::RecompileConcurrent(Handle<JSFunction> closure, | 1115 static bool GetOptimizedCodeLater(CompilationInfo* info) { |
| 1068 uint32_t osr_pc_offset) { | 1116 Isolate* isolate = info->isolate(); |
| 1069 bool compiling_for_osr = (osr_pc_offset != 0); | |
| 1070 | |
| 1071 Isolate* isolate = closure->GetIsolate(); | |
| 1072 // Here we prepare compile data for the concurrent recompilation thread, but | |
| 1073 // this still happens synchronously and interrupts execution. | |
| 1074 Logger::TimerEventScope timer( | |
| 1075 isolate, Logger::TimerEventScope::v8_recompile_synchronous); | |
| 1076 | |
| 1077 if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) { | 1117 if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) { |
| 1078 if (FLAG_trace_concurrent_recompilation) { | 1118 if (FLAG_trace_concurrent_recompilation) { |
| 1079 PrintF(" ** Compilation queue full, will retry optimizing "); | 1119 PrintF(" ** Compilation queue full, will retry optimizing "); |
| 1080 closure->PrintName(); | 1120 info->closure()->PrintName(); |
| 1081 PrintF(" on next run.\n"); | 1121 PrintF(" later.\n"); |
| 1082 } | 1122 } |
| 1083 return false; | 1123 return false; |
| 1084 } | 1124 } |
| 1085 | 1125 |
| 1086 SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(closure)); | 1126 CompilationHandleScope handle_scope(info); |
| 1127 if (!CompileOptimizedPrologue(info)) return false; |
| 1128 info->SaveHandles(); // Copy handles to the compilation handle scope. |
| 1129 |
| 1130 Logger::TimerEventScope timer( |
| 1131 isolate, Logger::TimerEventScope::v8_recompile_synchronous); |
| 1132 |
| 1133 OptimizedCompileJob* job = new(info->zone()) OptimizedCompileJob(info); |
| 1134 OptimizedCompileJob::Status status = job->CreateGraph(); |
| 1135 if (status != OptimizedCompileJob::SUCCEEDED) return false; |
| 1136 isolate->optimizing_compiler_thread()->QueueForOptimization(job); |
| 1137 |
| 1138 if (FLAG_trace_concurrent_recompilation) { |
| 1139 PrintF(" ** Queued "); |
| 1140 info->closure()->PrintName(); |
| 1141 if (info->is_osr()) { |
| 1142 PrintF(" for concurrent OSR at %d.\n", info->osr_ast_id().ToInt()); |
| 1143 } else { |
| 1144 PrintF(" for concurrent optimization.\n"); |
| 1145 } |
| 1146 } |
| 1147 return true; |
| 1148 } |
| 1149 |
| 1150 |
| 1151 Handle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function, |
| 1152 Handle<Code> current_code, |
| 1153 ConcurrencyMode mode, |
| 1154 BailoutId osr_ast_id) { |
| 1155 Handle<Code> cached_code = GetCodeFromOptimizedCodeMap(function, osr_ast_id); |
| 1156 if (!cached_code.is_null()) return cached_code; |
| 1157 |
| 1158 SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(function)); |
| 1159 Isolate* isolate = info->isolate(); |
| 1160 VMState<COMPILER> state(isolate); |
| 1161 ASSERT(!isolate->has_pending_exception()); |
| 1162 PostponeInterruptsScope postpone(isolate); |
| 1163 |
| 1087 Handle<SharedFunctionInfo> shared = info->shared_info(); | 1164 Handle<SharedFunctionInfo> shared = info->shared_info(); |
| 1165 ASSERT_NE(ScopeInfo::Empty(isolate), shared->scope_info()); |
| 1166 int compiled_size = shared->end_position() - shared->start_position(); |
| 1167 isolate->counters()->total_compile_size()->Increment(compiled_size); |
| 1168 current_code->set_profiler_ticks(0); |
| 1088 | 1169 |
| 1089 if (compiling_for_osr) { | 1170 info->SetOptimizing(osr_ast_id, current_code); |
| 1090 BailoutId osr_ast_id = | |
| 1091 shared->code()->TranslatePcOffsetToAstId(osr_pc_offset); | |
| 1092 ASSERT(!osr_ast_id.IsNone()); | |
| 1093 info->SetOptimizing(osr_ast_id); | |
| 1094 info->set_osr_pc_offset(osr_pc_offset); | |
| 1095 | 1171 |
| 1096 if (FLAG_trace_osr) { | 1172 if (mode == CONCURRENT) { |
| 1097 PrintF("[COSR - attempt to queue "); | 1173 if (GetOptimizedCodeLater(info.get())) { |
| 1098 closure->PrintName(); | 1174 info.Detach(); // The background recompile job owns this now. |
| 1099 PrintF(" at AST id %d]\n", osr_ast_id.ToInt()); | 1175 return isolate->builtins()->InOptimizationQueue(); |
| 1100 } | 1176 } |
| 1101 } else { | 1177 } else { |
| 1102 info->SetOptimizing(BailoutId::None()); | 1178 if (GetOptimizedCodeNow(info.get())) return info->code(); |
| 1103 } | 1179 } |
| 1104 | 1180 |
| 1105 VMState<COMPILER> state(isolate); | 1181 // Failed. |
| 1106 PostponeInterruptsScope postpone(isolate); | 1182 if (FLAG_trace_opt) { |
| 1107 | 1183 PrintF("[failed to optimize "); |
| 1108 int compiled_size = shared->end_position() - shared->start_position(); | 1184 function->PrintName(); |
| 1109 isolate->counters()->total_compile_size()->Increment(compiled_size); | 1185 PrintF("]\n"); |
| 1110 | |
| 1111 { | |
| 1112 CompilationHandleScope handle_scope(*info); | |
| 1113 | |
| 1114 if (!compiling_for_osr && InstallCodeFromOptimizedCodeMap(*info)) { | |
| 1115 return true; | |
| 1116 } | |
| 1117 | |
| 1118 if (Parser::Parse(*info)) { | |
| 1119 LanguageMode language_mode = info->function()->language_mode(); | |
| 1120 info->SetLanguageMode(language_mode); | |
| 1121 shared->set_language_mode(language_mode); | |
| 1122 info->SaveHandles(); | |
| 1123 | |
| 1124 if (Rewriter::Rewrite(*info) && Scope::Analyze(*info)) { | |
| 1125 RecompileJob* job = new(info->zone()) RecompileJob(*info); | |
| 1126 RecompileJob::Status status = job->CreateGraph(); | |
| 1127 if (status == RecompileJob::SUCCEEDED) { | |
| 1128 info.Detach(); | |
| 1129 shared->code()->set_profiler_ticks(0); | |
| 1130 isolate->optimizing_compiler_thread()->QueueForOptimization(job); | |
| 1131 ASSERT(!isolate->has_pending_exception()); | |
| 1132 return true; | |
| 1133 } else if (status == RecompileJob::BAILED_OUT) { | |
| 1134 isolate->clear_pending_exception(); | |
| 1135 InstallFullCode(*info); | |
| 1136 } | |
| 1137 } | |
| 1138 } | |
| 1139 } | 1186 } |
| 1140 | 1187 |
| 1141 if (isolate->has_pending_exception()) isolate->clear_pending_exception(); | 1188 if (isolate->has_pending_exception()) isolate->clear_pending_exception(); |
| 1142 return false; | 1189 return Handle<Code>::null(); |
| 1143 } | 1190 } |
| 1144 | 1191 |
| 1145 | 1192 |
| 1146 Handle<Code> Compiler::InstallOptimizedCode(RecompileJob* job) { | 1193 Handle<Code> Compiler::GetConcurrentlyOptimizedCode(OptimizedCompileJob* job) { |
| 1194 // Take ownership of compilation info. Deleting compilation info |
| 1195 // also tears down the zone and the recompile job. |
| 1147 SmartPointer<CompilationInfo> info(job->info()); | 1196 SmartPointer<CompilationInfo> info(job->info()); |
| 1148 // The function may have already been optimized by OSR. Simply continue. | 1197 Isolate* isolate = info->isolate(); |
| 1149 // Except when OSR already disabled optimization for some reason. | 1198 |
| 1150 if (info->shared_info()->optimization_disabled()) { | 1199 VMState<COMPILER> state(isolate); |
| 1151 info->AbortOptimization(); | 1200 Logger::TimerEventScope timer( |
| 1152 InstallFullCode(*info); | 1201 isolate, Logger::TimerEventScope::v8_recompile_synchronous); |
| 1153 if (FLAG_trace_concurrent_recompilation) { | 1202 |
| 1154 PrintF(" ** aborting optimization for "); | 1203 Handle<SharedFunctionInfo> shared = info->shared_info(); |
| 1155 info->closure()->PrintName(); | 1204 shared->code()->set_profiler_ticks(0); |
| 1156 PrintF(" as it has been disabled.\n"); | 1205 |
| 1157 } | 1206 // 1) Optimization may have failed. |
| 1158 ASSERT(!info->closure()->IsInRecompileQueue()); | 1207 // 2) The function may have already been optimized by OSR. Simply continue. |
| 1208 // Except when OSR already disabled optimization for some reason. |
| 1209 // 3) The code may have already been invalidated due to dependency change. |
| 1210 // 4) Debugger may have been activated. |
| 1211 |
| 1212 if (job->last_status() != OptimizedCompileJob::SUCCEEDED || |
| 1213 shared->optimization_disabled() || |
| 1214 info->HasAbortedDueToDependencyChange() || |
| 1215 isolate->DebuggerHasBreakPoints()) { |
| 1159 return Handle<Code>::null(); | 1216 return Handle<Code>::null(); |
| 1160 } | 1217 } |
| 1161 | 1218 |
| 1162 Isolate* isolate = info->isolate(); | 1219 if (job->GenerateCode() != OptimizedCompileJob::SUCCEEDED) { |
| 1163 VMState<COMPILER> state(isolate); | 1220 return Handle<Code>::null(); |
| 1164 Logger::TimerEventScope timer( | |
| 1165 isolate, Logger::TimerEventScope::v8_recompile_synchronous); | |
| 1166 // If crankshaft succeeded, install the optimized code else install | |
| 1167 // the unoptimized code. | |
| 1168 RecompileJob::Status status = job->last_status(); | |
| 1169 if (info->HasAbortedDueToDependencyChange()) { | |
| 1170 info->set_bailout_reason(kBailedOutDueToDependencyChange); | |
| 1171 status = job->AbortOptimization(); | |
| 1172 } else if (status != RecompileJob::SUCCEEDED) { | |
| 1173 info->set_bailout_reason(kFailedBailedOutLastTime); | |
| 1174 status = job->AbortOptimization(); | |
| 1175 } else if (isolate->DebuggerHasBreakPoints()) { | |
| 1176 info->set_bailout_reason(kDebuggerIsActive); | |
| 1177 status = job->AbortOptimization(); | |
| 1178 } else { | |
| 1179 status = job->GenerateAndInstallCode(); | |
| 1180 ASSERT(status == RecompileJob::SUCCEEDED || | |
| 1181 status == RecompileJob::BAILED_OUT); | |
| 1182 } | 1221 } |
| 1183 | 1222 |
| 1184 InstallCodeCommon(*info); | 1223 Compiler::RecordFunctionCompilation( |
| 1185 if (status == RecompileJob::SUCCEEDED) { | 1224 Logger::LAZY_COMPILE_TAG, info.get(), shared); |
| 1186 Handle<Code> code = info->code(); | 1225 if (info->shared_info()->SearchOptimizedCodeMap( |
| 1187 ASSERT(info->shared_info()->scope_info() != ScopeInfo::Empty(isolate)); | 1226 info->context()->native_context(), info->osr_ast_id()) == -1) { |
| 1188 info->closure()->ReplaceCode(*code); | 1227 InsertCodeIntoOptimizedCodeMap(info.get()); |
| 1189 if (info->shared_info()->SearchOptimizedCodeMap( | |
| 1190 info->closure()->context()->native_context()) == -1) { | |
| 1191 InsertCodeIntoOptimizedCodeMap(*info); | |
| 1192 } | |
| 1193 if (FLAG_trace_concurrent_recompilation) { | |
| 1194 PrintF(" ** Optimized code for "); | |
| 1195 info->closure()->PrintName(); | |
| 1196 PrintF(" installed.\n"); | |
| 1197 } | |
| 1198 } else { | |
| 1199 info->AbortOptimization(); | |
| 1200 InstallFullCode(*info); | |
| 1201 } | 1228 } |
| 1202 // Optimized code is finally replacing unoptimized code. Reset the latter's | 1229 |
| 1203 // profiler ticks to prevent too soon re-opt after a deopt. | 1230 if (FLAG_trace_concurrent_recompilation) { |
| 1204 info->shared_info()->code()->set_profiler_ticks(0); | 1231 PrintF(" ** Optimized code for "); |
| 1205 ASSERT(!info->closure()->IsInRecompileQueue()); | 1232 info->closure()->PrintName(); |
| 1206 return (status == RecompileJob::SUCCEEDED) ? info->code() | 1233 PrintF(" generated.\n"); |
| 1207 : Handle<Code>::null(); | 1234 } |
| 1235 |
| 1236 return Handle<Code>(*info->code()); |
| 1208 } | 1237 } |
| 1209 | 1238 |
| 1210 | 1239 |
| 1211 Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, | |
| 1212 Handle<Script> script) { | |
| 1213 // Precondition: code has been parsed and scopes have been analyzed. | |
| 1214 CompilationInfoWithZone info(script); | |
| 1215 info.SetFunction(literal); | |
| 1216 info.SetScope(literal->scope()); | |
| 1217 info.SetLanguageMode(literal->scope()->language_mode()); | |
| 1218 | |
| 1219 Isolate* isolate = info.isolate(); | |
| 1220 Factory* factory = isolate->factory(); | |
| 1221 LiveEditFunctionTracker live_edit_tracker(isolate, literal); | |
| 1222 // Determine if the function can be lazily compiled. This is necessary to | |
| 1223 // allow some of our builtin JS files to be lazily compiled. These | |
| 1224 // builtins cannot be handled lazily by the parser, since we have to know | |
| 1225 // if a function uses the special natives syntax, which is something the | |
| 1226 // parser records. | |
| 1227 // If the debugger requests compilation for break points, we cannot be | |
| 1228 // aggressive about lazy compilation, because it might trigger compilation | |
| 1229 // of functions without an outer context when setting a breakpoint through | |
| 1230 // Debug::FindSharedFunctionInfoInScript. | |
| 1231 bool allow_lazy_without_ctx = literal->AllowsLazyCompilationWithoutContext(); | |
| 1232 bool allow_lazy = literal->AllowsLazyCompilation() && | |
| 1233 !DebuggerWantsEagerCompilation(&info, allow_lazy_without_ctx); | |
| 1234 | |
| 1235 Handle<ScopeInfo> scope_info(ScopeInfo::Empty(isolate)); | |
| 1236 | |
| 1237 // Generate code | |
| 1238 if (FLAG_lazy && allow_lazy && !literal->is_parenthesized()) { | |
| 1239 Handle<Code> code = isolate->builtins()->LazyCompile(); | |
| 1240 info.SetCode(code); | |
| 1241 } else if (GenerateCode(&info)) { | |
| 1242 ASSERT(!info.code().is_null()); | |
| 1243 scope_info = ScopeInfo::Create(info.scope(), info.zone()); | |
| 1244 } else { | |
| 1245 return Handle<SharedFunctionInfo>::null(); | |
| 1246 } | |
| 1247 | |
| 1248 // Create a shared function info object. | |
| 1249 Handle<SharedFunctionInfo> result = | |
| 1250 factory->NewSharedFunctionInfo(literal->name(), | |
| 1251 literal->materialized_literal_count(), | |
| 1252 literal->is_generator(), | |
| 1253 info.code(), | |
| 1254 scope_info); | |
| 1255 SetFunctionInfo(result, literal, false, script); | |
| 1256 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result); | |
| 1257 result->set_allows_lazy_compilation(allow_lazy); | |
| 1258 result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx); | |
| 1259 | |
| 1260 // Set the expected number of properties for instances and return | |
| 1261 // the resulting function. | |
| 1262 SetExpectedNofPropertiesFromEstimate(result, | |
| 1263 literal->expected_property_count()); | |
| 1264 live_edit_tracker.RecordFunctionInfo(result, literal, info.zone()); | |
| 1265 return result; | |
| 1266 } | |
| 1267 | |
| 1268 | |
| 1269 // Sets the function info on a function. | |
| 1270 // The start_position points to the first '(' character after the function name | |
| 1271 // in the full script source. When counting characters in the script source the | |
| 1272 // the first character is number 0 (not 1). | |
| 1273 void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, | |
| 1274 FunctionLiteral* lit, | |
| 1275 bool is_toplevel, | |
| 1276 Handle<Script> script) { | |
| 1277 function_info->set_length(lit->parameter_count()); | |
| 1278 function_info->set_formal_parameter_count(lit->parameter_count()); | |
| 1279 function_info->set_script(*script); | |
| 1280 function_info->set_function_token_position(lit->function_token_position()); | |
| 1281 function_info->set_start_position(lit->start_position()); | |
| 1282 function_info->set_end_position(lit->end_position()); | |
| 1283 function_info->set_is_expression(lit->is_expression()); | |
| 1284 function_info->set_is_anonymous(lit->is_anonymous()); | |
| 1285 function_info->set_is_toplevel(is_toplevel); | |
| 1286 function_info->set_inferred_name(*lit->inferred_name()); | |
| 1287 function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); | |
| 1288 function_info->set_allows_lazy_compilation_without_context( | |
| 1289 lit->AllowsLazyCompilationWithoutContext()); | |
| 1290 function_info->set_language_mode(lit->language_mode()); | |
| 1291 function_info->set_uses_arguments(lit->scope()->arguments() != NULL); | |
| 1292 function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); | |
| 1293 function_info->set_ast_node_count(lit->ast_node_count()); | |
| 1294 function_info->set_is_function(lit->is_function()); | |
| 1295 function_info->set_dont_optimize_reason(lit->dont_optimize_reason()); | |
| 1296 function_info->set_dont_inline(lit->flags()->Contains(kDontInline)); | |
| 1297 function_info->set_dont_cache(lit->flags()->Contains(kDontCache)); | |
| 1298 function_info->set_is_generator(lit->is_generator()); | |
| 1299 } | |
| 1300 | |
| 1301 | |
| 1302 void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, | 1240 void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, |
| 1303 CompilationInfo* info, | 1241 CompilationInfo* info, |
| 1304 Handle<SharedFunctionInfo> shared) { | 1242 Handle<SharedFunctionInfo> shared) { |
| 1305 // SharedFunctionInfo is passed separately, because if CompilationInfo | 1243 // SharedFunctionInfo is passed separately, because if CompilationInfo |
| 1306 // was created using Script object, it will not have it. | 1244 // was created using Script object, it will not have it. |
| 1307 | 1245 |
| 1308 // Log the code generation. If source information is available include | 1246 // Log the code generation. If source information is available include |
| 1309 // script name and line number. Check explicitly whether logging is | 1247 // script name and line number. Check explicitly whether logging is |
| 1310 // enabled as finding the line number is not free. | 1248 // enabled as finding the line number is not free. |
| 1311 if (info->isolate()->logger()->is_logging_code_events() || | 1249 if (info->isolate()->logger()->is_logging_code_events() || |
| 1312 info->isolate()->cpu_profiler()->is_profiling()) { | 1250 info->isolate()->cpu_profiler()->is_profiling()) { |
| 1313 Handle<Script> script = info->script(); | 1251 Handle<Script> script = info->script(); |
| 1314 Handle<Code> code = info->code(); | 1252 Handle<Code> code = info->code(); |
| 1315 if (*code == info->isolate()->builtins()->builtin(Builtins::kLazyCompile)) | 1253 if (code.is_identical_to(info->isolate()->builtins()->CompileUnoptimized())) |
| 1316 return; | 1254 return; |
| 1317 int line_num = GetScriptLineNumber(script, shared->start_position()) + 1; | 1255 int line_num = GetScriptLineNumber(script, shared->start_position()) + 1; |
| 1318 int column_num = | 1256 int column_num = |
| 1319 GetScriptColumnNumber(script, shared->start_position()) + 1; | 1257 GetScriptColumnNumber(script, shared->start_position()) + 1; |
| 1320 USE(line_num); | 1258 USE(line_num); |
| 1321 if (script->name()->IsString()) { | 1259 String* script_name = script->name()->IsString() |
| 1322 PROFILE(info->isolate(), | 1260 ? String::cast(script->name()) |
| 1323 CodeCreateEvent(Logger::ToNativeByScript(tag, *script), | 1261 : info->isolate()->heap()->empty_string(); |
| 1324 *code, | 1262 Logger::LogEventsAndTags log_tag = Logger::ToNativeByScript(tag, *script); |
| 1325 *shared, | 1263 PROFILE(info->isolate(), CodeCreateEvent( |
| 1326 info, | 1264 log_tag, *code, *shared, info, script_name, line_num, column_num)); |
| 1327 String::cast(script->name()), | |
| 1328 line_num, | |
| 1329 column_num)); | |
| 1330 } else { | |
| 1331 PROFILE(info->isolate(), | |
| 1332 CodeCreateEvent(Logger::ToNativeByScript(tag, *script), | |
| 1333 *code, | |
| 1334 *shared, | |
| 1335 info, | |
| 1336 info->isolate()->heap()->empty_string(), | |
| 1337 line_num, | |
| 1338 column_num)); | |
| 1339 } | |
| 1340 } | 1265 } |
| 1341 | 1266 |
| 1342 GDBJIT(AddCode(Handle<String>(shared->DebugName()), | 1267 GDBJIT(AddCode(Handle<String>(shared->DebugName()), |
| 1343 Handle<Script>(info->script()), | 1268 Handle<Script>(info->script()), |
| 1344 Handle<Code>(info->code()), | 1269 Handle<Code>(info->code()), |
| 1345 info)); | 1270 info)); |
| 1346 } | 1271 } |
| 1347 | 1272 |
| 1348 | 1273 |
| 1349 CompilationPhase::CompilationPhase(const char* name, CompilationInfo* info) | 1274 CompilationPhase::CompilationPhase(const char* name, CompilationInfo* info) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1370 AllowHandleDereference allow_deref; | 1295 AllowHandleDereference allow_deref; |
| 1371 bool tracing_on = info()->IsStub() | 1296 bool tracing_on = info()->IsStub() |
| 1372 ? FLAG_trace_hydrogen_stubs | 1297 ? FLAG_trace_hydrogen_stubs |
| 1373 : (FLAG_trace_hydrogen && | 1298 : (FLAG_trace_hydrogen && |
| 1374 info()->closure()->PassesFilter(FLAG_trace_hydrogen_filter)); | 1299 info()->closure()->PassesFilter(FLAG_trace_hydrogen_filter)); |
| 1375 return (tracing_on && | 1300 return (tracing_on && |
| 1376 OS::StrChr(const_cast<char*>(FLAG_trace_phase), name_[0]) != NULL); | 1301 OS::StrChr(const_cast<char*>(FLAG_trace_phase), name_[0]) != NULL); |
| 1377 } | 1302 } |
| 1378 | 1303 |
| 1379 } } // namespace v8::internal | 1304 } } // namespace v8::internal |
| OLD | NEW |