1 // Copyright 2012 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 "compiler.h" 31 32 #include "bootstrapper.h" 33 #include "codegen.h" 34 #include "compilation-cache.h" 35 #include "cpu-profiler.h" 36 #include "debug.h" 37 #include "deoptimizer.h" 38 #include "full-codegen.h" 39 #include "gdb-jit.h" 40 #include "typing.h" 41 #include "hydrogen.h" 42 #include "isolate-inl.h" 43 #include "lithium.h" 44 #include "liveedit.h" 45 #include "parser.h" 46 #include "rewriter.h" 47 #include "runtime-profiler.h" 48 #include "scanner-character-streams.h" 49 #include "scopeinfo.h" 50 #include "scopes.h" 51 #include "vm-state-inl.h" 52 53 namespace v8 { 54 namespace internal { 55 56 57 CompilationInfo::CompilationInfo(Handle<Script> script, 58 Zone* zone) 59 : flags_(LanguageModeField::encode(CLASSIC_MODE)), 60 script_(script), 61 osr_ast_id_(BailoutId::None()) { 62 Initialize(script->GetIsolate(), BASE, zone); 63 } 64 65 66 CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info, 67 Zone* zone) 68 : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)), 69 shared_info_(shared_info), 70 script_(Handle<Script>(Script::cast(shared_info->script()))), 71 osr_ast_id_(BailoutId::None()) { 72 Initialize(script_->GetIsolate(), BASE, zone); 73 } 74 75 76 CompilationInfo::CompilationInfo(Handle<JSFunction> closure, 77 Zone* zone) 78 : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)), 79 closure_(closure), 80 shared_info_(Handle<SharedFunctionInfo>(closure->shared())), 81 script_(Handle<Script>(Script::cast(shared_info_->script()))), 82 context_(closure->context()), 83 osr_ast_id_(BailoutId::None()) { 84 Initialize(script_->GetIsolate(), BASE, zone); 85 } 86 87 88 CompilationInfo::CompilationInfo(HydrogenCodeStub* stub, 89 Isolate* isolate, 90 Zone* zone) 91 : flags_(LanguageModeField::encode(CLASSIC_MODE) | 92 IsLazy::encode(true)), 93 osr_ast_id_(BailoutId::None()) { 94 Initialize(isolate, STUB, zone); 95 code_stub_ = stub; 96 } 97 98 99 void CompilationInfo::Initialize(Isolate* isolate, 100 Mode mode, 101 Zone* zone) { 102 isolate_ = isolate; 103 function_ = NULL; 104 scope_ = NULL; 105 global_scope_ = NULL; 106 extension_ = NULL; 107 pre_parse_data_ = NULL; 108 zone_ = zone; 109 deferred_handles_ = NULL; 110 code_stub_ = NULL; 111 prologue_offset_ = kPrologueOffsetNotSet; 112 opt_count_ = shared_info().is_null() ? 0 : shared_info()->opt_count(); 113 no_frame_ranges_ = isolate->cpu_profiler()->is_profiling() 114 ? new List<OffsetRange>(2) : NULL; 115 for (int i = 0; i < DependentCode::kGroupCount; i++) { 116 dependencies_[i] = NULL; 117 } 118 if (mode == STUB) { 119 mode_ = STUB; 120 return; 121 } 122 mode_ = V8::UseCrankshaft() ? mode : NONOPT; 123 abort_due_to_dependency_ = false; 124 if (script_->type()->value() == Script::TYPE_NATIVE) { 125 MarkAsNative(); 126 } 127 if (!shared_info_.is_null()) { 128 ASSERT(language_mode() == CLASSIC_MODE); 129 SetLanguageMode(shared_info_->language_mode()); 130 } 131 set_bailout_reason(kUnknown); 132 } 133 134 135 CompilationInfo::~CompilationInfo() { 136 delete deferred_handles_; 137 delete no_frame_ranges_; 138 #ifdef DEBUG 139 // Check that no dependent maps have been added or added dependent maps have 140 // been rolled back or committed. 141 for (int i = 0; i < DependentCode::kGroupCount; i++) { 142 ASSERT_EQ(NULL, dependencies_[i]); 143 } 144 #endif // DEBUG 145 } 146 147 148 void CompilationInfo::CommitDependencies(Handle<Code> code) { 149 for (int i = 0; i < DependentCode::kGroupCount; i++) { 150 ZoneList<Handle<HeapObject> >* group_objects = dependencies_[i]; 151 if (group_objects == NULL) continue; 152 ASSERT(!object_wrapper_.is_null()); 153 for (int j = 0; j < group_objects->length(); j++) { 154 DependentCode::DependencyGroup group = 155 static_cast<DependentCode::DependencyGroup>(i); 156 DependentCode* dependent_code = 157 DependentCode::ForObject(group_objects->at(j), group); 158 dependent_code->UpdateToFinishedCode(group, this, *code); 159 } 160 dependencies_[i] = NULL; // Zone-allocated, no need to delete. 161 } 162 } 163 164 165 void CompilationInfo::RollbackDependencies() { 166 // Unregister from all dependent maps if not yet committed. 167 for (int i = 0; i < DependentCode::kGroupCount; i++) { 168 ZoneList<Handle<HeapObject> >* group_objects = dependencies_[i]; 169 if (group_objects == NULL) continue; 170 for (int j = 0; j < group_objects->length(); j++) { 171 DependentCode::DependencyGroup group = 172 static_cast<DependentCode::DependencyGroup>(i); 173 DependentCode* dependent_code = 174 DependentCode::ForObject(group_objects->at(j), group); 175 dependent_code->RemoveCompilationInfo(group, this); 176 } 177 dependencies_[i] = NULL; // Zone-allocated, no need to delete. 178 } 179 } 180 181 182 int CompilationInfo::num_parameters() const { 183 ASSERT(!IsStub()); 184 return scope()->num_parameters(); 185 } 186 187 188 int CompilationInfo::num_heap_slots() const { 189 if (IsStub()) { 190 return 0; 191 } else { 192 return scope()->num_heap_slots(); 193 } 194 } 195 196 197 Code::Flags CompilationInfo::flags() const { 198 if (IsStub()) { 199 return Code::ComputeFlags(code_stub()->GetCodeKind(), 200 code_stub()->GetICState(), 201 code_stub()->GetExtraICState(), 202 code_stub()->GetStubType(), 203 code_stub()->GetStubFlags()); 204 } else { 205 return Code::ComputeFlags(Code::OPTIMIZED_FUNCTION); 206 } 207 } 208 209 210 // Disable optimization for the rest of the compilation pipeline. 211 void CompilationInfo::DisableOptimization() { 212 bool is_optimizable_closure = 213 FLAG_optimize_closures && 214 closure_.is_null() && 215 !scope_->HasTrivialOuterContext() && 216 !scope_->outer_scope_calls_non_strict_eval() && 217 !scope_->inside_with(); 218 SetMode(is_optimizable_closure ? BASE : NONOPT); 219 } 220 221 222 // Primitive functions are unlikely to be picked up by the stack-walking 223 // profiler, so they trigger their own optimization when they're called 224 // for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time. 225 bool CompilationInfo::ShouldSelfOptimize() { 226 return FLAG_self_optimization && 227 FLAG_crankshaft && 228 !function()->flags()->Contains(kDontSelfOptimize) && 229 !function()->flags()->Contains(kDontOptimize) && 230 function()->scope()->AllowsLazyCompilation() && 231 (shared_info().is_null() || !shared_info()->optimization_disabled()); 232 } 233 234 235 void CompilationInfo::AbortOptimization() { 236 Handle<Code> code(shared_info()->code()); 237 SetCode(code); 238 } 239 240 241 // Determine whether to use the full compiler for all code. If the flag 242 // --always-full-compiler is specified this is the case. For the virtual frame 243 // based compiler the full compiler is also used if a debugger is connected, as 244 // the code from the full compiler supports mode precise break points. For the 245 // crankshaft adaptive compiler debugging the optimized code is not possible at 246 // all. However crankshaft support recompilation of functions, so in this case 247 // the full compiler need not be be used if a debugger is attached, but only if 248 // break points has actually been set. 249 static bool IsDebuggerActive(Isolate* isolate) { 250 #ifdef ENABLE_DEBUGGER_SUPPORT 251 return V8::UseCrankshaft() ? 252 isolate->debug()->has_break_points() : 253 isolate->debugger()->IsDebuggerActive(); 254 #else 255 return false; 256 #endif 257 } 258 259 260 static bool AlwaysFullCompiler(Isolate* isolate) { 261 return FLAG_always_full_compiler || IsDebuggerActive(isolate); 262 } 263 264 265 void OptimizingCompiler::RecordOptimizationStats() { 266 Handle<JSFunction> function = info()->closure(); 267 int opt_count = function->shared()->opt_count(); 268 function->shared()->set_opt_count(opt_count + 1); 269 double ms_creategraph = 270 static_cast<double>(time_taken_to_create_graph_) / 1000; 271 double ms_optimize = static_cast<double>(time_taken_to_optimize_) / 1000; 272 double ms_codegen = static_cast<double>(time_taken_to_codegen_) / 1000; 273 if (FLAG_trace_opt) { 274 PrintF("[optimizing "); 275 function->ShortPrint(); 276 PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize, 277 ms_codegen); 278 } 279 if (FLAG_trace_opt_stats) { 280 static double compilation_time = 0.0; 281 static int compiled_functions = 0; 282 static int code_size = 0; 283 284 compilation_time += (ms_creategraph + ms_optimize + ms_codegen); 285 compiled_functions++; 286 code_size += function->shared()->SourceSize(); 287 PrintF("Compiled: %d functions with %d byte source size in %fms.\n", 288 compiled_functions, 289 code_size, 290 compilation_time); 291 } 292 if (FLAG_hydrogen_stats) { 293 isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_create_graph_, 294 time_taken_to_optimize_, 295 time_taken_to_codegen_); 296 } 297 } 298 299 300 // A return value of true indicates the compilation pipeline is still 301 // going, not necessarily that we optimized the code. 302 static bool MakeCrankshaftCode(CompilationInfo* info) { 303 OptimizingCompiler compiler(info); 304 OptimizingCompiler::Status status = compiler.CreateGraph(); 305 306 if (status != OptimizingCompiler::SUCCEEDED) { 307 return status != OptimizingCompiler::FAILED; 308 } 309 status = compiler.OptimizeGraph(); 310 if (status != OptimizingCompiler::SUCCEEDED) { 311 status = compiler.AbortOptimization(); 312 return status != OptimizingCompiler::FAILED; 313 } 314 status = compiler.GenerateAndInstallCode(); 315 return status != OptimizingCompiler::FAILED; 316 } 317 318 319 OptimizingCompiler::Status OptimizingCompiler::CreateGraph() { 320 ASSERT(V8::UseCrankshaft()); 321 ASSERT(info()->IsOptimizing()); 322 ASSERT(!info()->IsCompilingForDebugging()); 323 324 // We should never arrive here if there is no code object on the 325 // shared function object. 326 Handle<Code> code(info()->shared_info()->code()); 327 ASSERT(code->kind() == Code::FUNCTION); 328 329 // We should never arrive here if optimization has been disabled on the 330 // shared function info. 331 ASSERT(!info()->shared_info()->optimization_disabled()); 332 333 // Fall back to using the full code generator if it's not possible 334 // to use the Hydrogen-based optimizing compiler. We already have 335 // generated code for this from the shared function object. 336 if (AlwaysFullCompiler(isolate())) { 337 info()->SetCode(code); 338 return SetLastStatus(BAILED_OUT); 339 } 340 341 // Limit the number of times we re-compile a functions with 342 // the optimizing compiler. 343 const int kMaxOptCount = 344 FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000; 345 if (info()->opt_count() > kMaxOptCount) { 346 info()->set_bailout_reason(kOptimizedTooManyTimes); 347 return AbortOptimization(); 348 } 349 350 // Due to an encoding limit on LUnallocated operands in the Lithium 351 // language, we cannot optimize functions with too many formal parameters 352 // or perform on-stack replacement for function with too many 353 // stack-allocated local variables. 354 // 355 // The encoding is as a signed value, with parameters and receiver using 356 // the negative indices and locals the non-negative ones. 357 const int parameter_limit = -LUnallocated::kMinFixedSlotIndex; 358 Scope* scope = info()->scope(); 359 if ((scope->num_parameters() + 1) > parameter_limit) { 360 info()->set_bailout_reason(kTooManyParameters); 361 return AbortOptimization(); 362 } 363 364 const int locals_limit = LUnallocated::kMaxFixedSlotIndex; 365 if (!info()->osr_ast_id().IsNone() && 366 scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) { 367 info()->set_bailout_reason(kTooManyParametersLocals); 368 return AbortOptimization(); 369 } 370 371 // Take --hydrogen-filter into account. 372 if (!info()->closure()->PassesHydrogenFilter()) { 373 info()->SetCode(code); 374 return SetLastStatus(BAILED_OUT); 375 } 376 377 // Recompile the unoptimized version of the code if the current version 378 // doesn't have deoptimization support. Alternatively, we may decide to 379 // run the full code generator to get a baseline for the compile-time 380 // performance of the hydrogen-based compiler. 381 bool should_recompile = !info()->shared_info()->has_deoptimization_support(); 382 if (should_recompile || FLAG_hydrogen_stats) { 383 int64_t start_ticks = 0; 384 if (FLAG_hydrogen_stats) { 385 start_ticks = OS::Ticks(); 386 } 387 CompilationInfoWithZone unoptimized(info()->shared_info()); 388 // Note that we use the same AST that we will use for generating the 389 // optimized code. 390 unoptimized.SetFunction(info()->function()); 391 unoptimized.SetScope(info()->scope()); 392 unoptimized.SetContext(info()->context()); 393 if (should_recompile) unoptimized.EnableDeoptimizationSupport(); 394 bool succeeded = FullCodeGenerator::MakeCode(&unoptimized); 395 if (should_recompile) { 396 if (!succeeded) return SetLastStatus(FAILED); 397 Handle<SharedFunctionInfo> shared = info()->shared_info(); 398 shared->EnableDeoptimizationSupport(*unoptimized.code()); 399 // The existing unoptimized code was replaced with the new one. 400 Compiler::RecordFunctionCompilation( 401 Logger::LAZY_COMPILE_TAG, &unoptimized, shared); 402 } 403 if (FLAG_hydrogen_stats) { 404 int64_t ticks = OS::Ticks() - start_ticks; 405 isolate()->GetHStatistics()->IncrementFullCodeGen(ticks); 406 } 407 } 408 409 // Check that the unoptimized, shared code is ready for 410 // optimizations. When using the always_opt flag we disregard the 411 // optimizable marker in the code object and optimize anyway. This 412 // is safe as long as the unoptimized code has deoptimization 413 // support. 414 ASSERT(FLAG_always_opt || code->optimizable()); 415 ASSERT(info()->shared_info()->has_deoptimization_support()); 416 417 if (FLAG_trace_hydrogen) { 418 Handle<String> name = info()->function()->debug_name(); 419 PrintF("-----------------------------------------------------------\n"); 420 PrintF("Compiling method %s using hydrogen\n", *name->ToCString()); 421 isolate()->GetHTracer()->TraceCompilation(info()); 422 } 423 424 // Type-check the function. 425 AstTyper::Run(info()); 426 427 graph_builder_ = new(info()->zone()) HOptimizedGraphBuilder(info()); 428 429 Timer t(this, &time_taken_to_create_graph_); 430 graph_ = graph_builder_->CreateGraph(); 431 432 if (isolate()->has_pending_exception()) { 433 info()->SetCode(Handle<Code>::null()); 434 return SetLastStatus(FAILED); 435 } 436 437 // The function being compiled may have bailed out due to an inline 438 // candidate bailing out. In such a case, we don't disable 439 // optimization on the shared_info. 440 ASSERT(!graph_builder_->inline_bailout() || graph_ == NULL); 441 if (graph_ == NULL) { 442 if (graph_builder_->inline_bailout()) { 443 info_->AbortOptimization(); 444 return SetLastStatus(BAILED_OUT); 445 } else { 446 return AbortOptimization(); 447 } 448 } 449 450 if (info()->HasAbortedDueToDependencyChange()) { 451 info_->set_bailout_reason(kBailedOutDueToDependencyChange); 452 info_->AbortOptimization(); 453 return SetLastStatus(BAILED_OUT); 454 } 455 456 return SetLastStatus(SUCCEEDED); 457 } 458 459 460 OptimizingCompiler::Status OptimizingCompiler::OptimizeGraph() { 461 DisallowHeapAllocation no_allocation; 462 DisallowHandleAllocation no_handles; 463 DisallowHandleDereference no_deref; 464 DisallowCodeDependencyChange no_dependency_change; 465 466 ASSERT(last_status() == SUCCEEDED); 467 Timer t(this, &time_taken_to_optimize_); 468 ASSERT(graph_ != NULL); 469 BailoutReason bailout_reason = kNoReason; 470 if (!graph_->Optimize(&bailout_reason)) { 471 if (bailout_reason == kNoReason) graph_builder_->Bailout(bailout_reason); 472 return SetLastStatus(BAILED_OUT); 473 } else { 474 chunk_ = LChunk::NewChunk(graph_); 475 if (chunk_ == NULL) { 476 return SetLastStatus(BAILED_OUT); 477 } 478 } 479 return SetLastStatus(SUCCEEDED); 480 } 481 482 483 OptimizingCompiler::Status OptimizingCompiler::GenerateAndInstallCode() { 484 ASSERT(last_status() == SUCCEEDED); 485 ASSERT(!info()->HasAbortedDueToDependencyChange()); 486 DisallowCodeDependencyChange no_dependency_change; 487 { // Scope for timer. 488 Timer timer(this, &time_taken_to_codegen_); 489 ASSERT(chunk_ != NULL); 490 ASSERT(graph_ != NULL); 491 // Deferred handles reference objects that were accessible during 492 // graph creation. To make sure that we don't encounter inconsistencies 493 // between graph creation and code generation, we disallow accessing 494 // objects through deferred handles during the latter, with exceptions. 495 DisallowDeferredHandleDereference no_deferred_handle_deref; 496 Handle<Code> optimized_code = chunk_->Codegen(); 497 if (optimized_code.is_null()) { 498 if (info()->bailout_reason() == kNoReason) { 499 info()->set_bailout_reason(kCodeGenerationFailed); 500 } 501 return AbortOptimization(); 502 } 503 info()->SetCode(optimized_code); 504 } 505 RecordOptimizationStats(); 506 return SetLastStatus(SUCCEEDED); 507 } 508 509 510 static bool GenerateCode(CompilationInfo* info) { 511 bool is_optimizing = V8::UseCrankshaft() && 512 !info->IsCompilingForDebugging() && 513 info->IsOptimizing(); 514 if (is_optimizing) { 515 Logger::TimerEventScope timer( 516 info->isolate(), Logger::TimerEventScope::v8_recompile_synchronous); 517 return MakeCrankshaftCode(info); 518 } else { 519 if (info->IsOptimizing()) { 520 // Have the CompilationInfo decide if the compilation should be 521 // BASE or NONOPT. 522 info->DisableOptimization(); 523 } 524 Logger::TimerEventScope timer( 525 info->isolate(), Logger::TimerEventScope::v8_compile_full_code); 526 return FullCodeGenerator::MakeCode(info); 527 } 528 } 529 530 531 static bool MakeCode(CompilationInfo* info) { 532 // Precondition: code has been parsed. Postcondition: the code field in 533 // the compilation info is set if compilation succeeded. 534 ASSERT(info->function() != NULL); 535 return Rewriter::Rewrite(info) && Scope::Analyze(info) && GenerateCode(info); 536 } 537 538 539 #ifdef ENABLE_DEBUGGER_SUPPORT 540 bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) { 541 // Precondition: code has been parsed. Postcondition: the code field in 542 // the compilation info is set if compilation succeeded. 543 bool succeeded = MakeCode(info); 544 if (!info->shared_info().is_null()) { 545 Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(), 546 info->zone()); 547 info->shared_info()->set_scope_info(*scope_info); 548 } 549 return succeeded; 550 } 551 #endif 552 553 554 static bool DebuggerWantsEagerCompilation(CompilationInfo* info, 555 bool allow_lazy_without_ctx = false) { 556 return LiveEditFunctionTracker::IsActive(info->isolate()) || 557 (info->isolate()->DebuggerHasBreakPoints() && !allow_lazy_without_ctx); 558 } 559 560 561 static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { 562 Isolate* isolate = info->isolate(); 563 PostponeInterruptsScope postpone(isolate); 564 565 ASSERT(!isolate->native_context().is_null()); 566 Handle<Script> script = info->script(); 567 // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile? 568 FixedArray* array = isolate->native_context()->embedder_data(); 569 script->set_context_data(array->get(0)); 570 571 #ifdef ENABLE_DEBUGGER_SUPPORT 572 if (info->is_eval()) { 573 script->set_compilation_type(Script::COMPILATION_TYPE_EVAL); 574 // For eval scripts add information on the function from which eval was 575 // called. 576 if (info->is_eval()) { 577 StackTraceFrameIterator it(isolate); 578 if (!it.done()) { 579 script->set_eval_from_shared(it.frame()->function()->shared()); 580 Code* code = it.frame()->LookupCode(); 581 int offset = static_cast<int>( 582 it.frame()->pc() - code->instruction_start()); 583 script->set_eval_from_instructions_offset(Smi::FromInt(offset)); 584 } 585 } 586 } 587 588 // Notify debugger 589 isolate->debugger()->OnBeforeCompile(script); 590 #endif 591 592 // Only allow non-global compiles for eval. 593 ASSERT(info->is_eval() || info->is_global()); 594 { 595 Parser parser(info); 596 if ((info->pre_parse_data() != NULL || 597 String::cast(script->source())->length() > FLAG_min_preparse_length) && 598 !DebuggerWantsEagerCompilation(info)) 599 parser.set_allow_lazy(true); 600 if (!parser.Parse()) { 601 return Handle<SharedFunctionInfo>::null(); 602 } 603 } 604 605 // Measure how long it takes to do the compilation; only take the 606 // rest of the function into account to avoid overlap with the 607 // parsing statistics. 608 HistogramTimer* rate = info->is_eval() 609 ? info->isolate()->counters()->compile_eval() 610 : info->isolate()->counters()->compile(); 611 HistogramTimerScope timer(rate); 612 613 // Compile the code. 614 FunctionLiteral* lit = info->function(); 615 LiveEditFunctionTracker live_edit_tracker(isolate, lit); 616 if (!MakeCode(info)) { 617 if (!isolate->has_pending_exception()) isolate->StackOverflow(); 618 return Handle<SharedFunctionInfo>::null(); 619 } 620 621 // Allocate function. 622 ASSERT(!info->code().is_null()); 623 Handle<SharedFunctionInfo> result = 624 isolate->factory()->NewSharedFunctionInfo( 625 lit->name(), 626 lit->materialized_literal_count(), 627 lit->is_generator(), 628 info->code(), 629 ScopeInfo::Create(info->scope(), info->zone())); 630 631 ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); 632 Compiler::SetFunctionInfo(result, lit, true, script); 633 634 if (script->name()->IsString()) { 635 PROFILE(isolate, CodeCreateEvent( 636 info->is_eval() 637 ? Logger::EVAL_TAG 638 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), 639 *info->code(), 640 *result, 641 info, 642 String::cast(script->name()))); 643 GDBJIT(AddCode(Handle<String>(String::cast(script->name())), 644 script, 645 info->code(), 646 info)); 647 } else { 648 PROFILE(isolate, CodeCreateEvent( 649 info->is_eval() 650 ? Logger::EVAL_TAG 651 : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), 652 *info->code(), 653 *result, 654 info, 655 isolate->heap()->empty_string())); 656 GDBJIT(AddCode(Handle<String>(), script, info->code(), info)); 657 } 658 659 // Hint to the runtime system used when allocating space for initial 660 // property space by setting the expected number of properties for 661 // the instances of the function. 662 SetExpectedNofPropertiesFromEstimate(result, lit->expected_property_count()); 663 664 script->set_compilation_state(Script::COMPILATION_STATE_COMPILED); 665 666 #ifdef ENABLE_DEBUGGER_SUPPORT 667 // Notify debugger 668 isolate->debugger()->OnAfterCompile( 669 script, Debugger::NO_AFTER_COMPILE_FLAGS); 670 #endif 671 672 live_edit_tracker.RecordFunctionInfo(result, lit, info->zone()); 673 674 return result; 675 } 676 677 678 Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, 679 Handle<Object> script_name, 680 int line_offset, 681 int column_offset, 682 bool is_shared_cross_origin, 683 Handle<Context> context, 684 v8::Extension* extension, 685 ScriptDataImpl* pre_data, 686 Handle<Object> script_data, 687 NativesFlag natives) { 688 Isolate* isolate = source->GetIsolate(); 689 int source_length = source->length(); 690 isolate->counters()->total_load_size()->Increment(source_length); 691 isolate->counters()->total_compile_size()->Increment(source_length); 692 693 // The VM is in the COMPILER state until exiting this function. 694 VMState<COMPILER> state(isolate); 695 696 CompilationCache* compilation_cache = isolate->compilation_cache(); 697 698 // Do a lookup in the compilation cache but not for extensions. 699 Handle<SharedFunctionInfo> result; 700 if (extension == NULL) { 701 result = compilation_cache->LookupScript(source, 702 script_name, 703 line_offset, 704 column_offset, 705 is_shared_cross_origin, 706 context); 707 } 708 709 if (result.is_null()) { 710 // No cache entry found. Do pre-parsing, if it makes sense, and compile 711 // the script. 712 // Building preparse data that is only used immediately after is only a 713 // saving if we might skip building the AST for lazily compiled functions. 714 // I.e., preparse data isn't relevant when the lazy flag is off, and 715 // for small sources, odds are that there aren't many functions 716 // that would be compiled lazily anyway, so we skip the preparse step 717 // in that case too. 718 719 // Create a script object describing the script to be compiled. 720 Handle<Script> script = isolate->factory()->NewScript(source); 721 if (natives == NATIVES_CODE) { 722 script->set_type(Smi::FromInt(Script::TYPE_NATIVE)); 723 } 724 if (!script_name.is_null()) { 725 script->set_name(*script_name); 726 script->set_line_offset(Smi::FromInt(line_offset)); 727 script->set_column_offset(Smi::FromInt(column_offset)); 728 } 729 script->set_is_shared_cross_origin(is_shared_cross_origin); 730 731 script->set_data(script_data.is_null() ? HEAP->undefined_value() 732 : *script_data); 733 734 // Compile the function and add it to the cache. 735 CompilationInfoWithZone info(script); 736 info.MarkAsGlobal(); 737 info.SetExtension(extension); 738 info.SetPreParseData(pre_data); 739 info.SetContext(context); 740 if (FLAG_use_strict) { 741 info.SetLanguageMode(FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE); 742 } 743 result = MakeFunctionInfo(&info); 744 if (extension == NULL && !result.is_null() && !result->dont_cache()) { 745 compilation_cache->PutScript(source, context, result); 746 } 747 } else { 748 if (result->ic_age() != HEAP->global_ic_age()) { 749 result->ResetForNewContext(HEAP->global_ic_age()); 750 } 751 } 752 753 if (result.is_null()) isolate->ReportPendingMessages(); 754 return result; 755 } 756 757 758 Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, 759 Handle<Context> context, 760 bool is_global, 761 LanguageMode language_mode, 762 ParseRestriction restriction, 763 int scope_position) { 764 Isolate* isolate = source->GetIsolate(); 765 int source_length = source->length(); 766 isolate->counters()->total_eval_size()->Increment(source_length); 767 isolate->counters()->total_compile_size()->Increment(source_length); 768 769 // The VM is in the COMPILER state until exiting this function. 770 VMState<COMPILER> state(isolate); 771 772 // Do a lookup in the compilation cache; if the entry is not there, invoke 773 // the compiler and add the result to the cache. 774 Handle<SharedFunctionInfo> result; 775 CompilationCache* compilation_cache = isolate->compilation_cache(); 776 result = compilation_cache->LookupEval(source, 777 context, 778 is_global, 779 language_mode, 780 scope_position); 781 782 if (result.is_null()) { 783 // Create a script object describing the script to be compiled. 784 Handle<Script> script = isolate->factory()->NewScript(source); 785 CompilationInfoWithZone info(script); 786 info.MarkAsEval(); 787 if (is_global) info.MarkAsGlobal(); 788 info.SetLanguageMode(language_mode); 789 info.SetParseRestriction(restriction); 790 info.SetContext(context); 791 result = MakeFunctionInfo(&info); 792 if (!result.is_null()) { 793 // Explicitly disable optimization for eval code. We're not yet prepared 794 // to handle eval-code in the optimizing compiler. 795 result->DisableOptimization(kEval); 796 797 // If caller is strict mode, the result must be in strict mode or 798 // extended mode as well, but not the other way around. Consider: 799 // eval("'use strict'; ..."); 800 ASSERT(language_mode != STRICT_MODE || !result->is_classic_mode()); 801 // If caller is in extended mode, the result must also be in 802 // extended mode. 803 ASSERT(language_mode != EXTENDED_MODE || 804 result->is_extended_mode()); 805 if (!result->dont_cache()) { 806 compilation_cache->PutEval( 807 source, context, is_global, result, scope_position); 808 } 809 } 810 } else { 811 if (result->ic_age() != HEAP->global_ic_age()) { 812 result->ResetForNewContext(HEAP->global_ic_age()); 813 } 814 } 815 816 return result; 817 } 818 819 820 static bool InstallFullCode(CompilationInfo* info) { 821 // Update the shared function info with the compiled code and the 822 // scope info. Please note, that the order of the shared function 823 // info initialization is important since set_scope_info might 824 // trigger a GC, causing the ASSERT below to be invalid if the code 825 // was flushed. By setting the code object last we avoid this. 826 Handle<SharedFunctionInfo> shared = info->shared_info(); 827 Handle<Code> code = info->code(); 828 CHECK(code->kind() == Code::FUNCTION); 829 Handle<JSFunction> function = info->closure(); 830 Handle<ScopeInfo> scope_info = 831 ScopeInfo::Create(info->scope(), info->zone()); 832 shared->set_scope_info(*scope_info); 833 shared->ReplaceCode(*code); 834 if (!function.is_null()) { 835 function->ReplaceCode(*code); 836 ASSERT(!function->IsOptimized()); 837 } 838 839 // Set the expected number of properties for instances. 840 FunctionLiteral* lit = info->function(); 841 int expected = lit->expected_property_count(); 842 SetExpectedNofPropertiesFromEstimate(shared, expected); 843 844 // Check the function has compiled code. 845 ASSERT(shared->is_compiled()); 846 shared->set_dont_optimize(lit->flags()->Contains(kDontOptimize)); 847 shared->set_dont_inline(lit->flags()->Contains(kDontInline)); 848 shared->set_ast_node_count(lit->ast_node_count()); 849 850 if (V8::UseCrankshaft() && 851 !function.is_null() && 852 !shared->optimization_disabled()) { 853 // If we're asked to always optimize, we compile the optimized 854 // version of the function right away - unless the debugger is 855 // active as it makes no sense to compile optimized code then. 856 if (FLAG_always_opt && 857 !Isolate::Current()->DebuggerHasBreakPoints()) { 858 CompilationInfoWithZone optimized(function); 859 optimized.SetOptimizing(BailoutId::None()); 860 return Compiler::CompileLazy(&optimized); 861 } 862 } 863 return true; 864 } 865 866 867 static void InstallCodeCommon(CompilationInfo* info) { 868 Handle<SharedFunctionInfo> shared = info->shared_info(); 869 Handle<Code> code = info->code(); 870 ASSERT(!code.is_null()); 871 872 // Set optimizable to false if this is disallowed by the shared 873 // function info, e.g., we might have flushed the code and must 874 // reset this bit when lazy compiling the code again. 875 if (shared->optimization_disabled()) code->set_optimizable(false); 876 877 if (shared->code() == *code) { 878 // Do not send compilation event for the same code twice. 879 return; 880 } 881 Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared); 882 } 883 884 885 static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { 886 Handle<Code> code = info->code(); 887 if (FLAG_cache_optimized_code && 888 info->osr_ast_id().IsNone() && 889 code->kind() == Code::OPTIMIZED_FUNCTION) { 890 Handle<JSFunction> function = info->closure(); 891 Handle<SharedFunctionInfo> shared(function->shared()); 892 Handle<FixedArray> literals(function->literals()); 893 Handle<Context> native_context(function->context()->native_context()); 894 SharedFunctionInfo::AddToOptimizedCodeMap( 895 shared, native_context, code, literals); 896 } 897 } 898 899 900 static bool InstallCodeFromOptimizedCodeMap(CompilationInfo* info) { 901 if (FLAG_cache_optimized_code && 902 info->osr_ast_id().IsNone() && 903 info->IsOptimizing()) { 904 Handle<SharedFunctionInfo> shared = info->shared_info(); 905 Handle<JSFunction> function = info->closure(); 906 ASSERT(!function.is_null()); 907 Handle<Context> native_context(function->context()->native_context()); 908 int index = shared->SearchOptimizedCodeMap(*native_context); 909 if (index > 0) { 910 if (FLAG_trace_opt) { 911 PrintF("[found optimized code for "); 912 function->ShortPrint(); 913 PrintF("]\n"); 914 } 915 // Caching of optimized code enabled and optimized code found. 916 shared->InstallFromOptimizedCodeMap(*function, index); 917 return true; 918 } 919 } 920 return false; 921 } 922 923 924 bool Compiler::CompileLazy(CompilationInfo* info) { 925 Isolate* isolate = info->isolate(); 926 927 // The VM is in the COMPILER state until exiting this function. 928 VMState<COMPILER> state(isolate); 929 930 PostponeInterruptsScope postpone(isolate); 931 932 Handle<SharedFunctionInfo> shared = info->shared_info(); 933 int compiled_size = shared->end_position() - shared->start_position(); 934 isolate->counters()->total_compile_size()->Increment(compiled_size); 935 936 if (InstallCodeFromOptimizedCodeMap(info)) return true; 937 938 // Generate the AST for the lazily compiled function. 939 if (Parser::Parse(info)) { 940 // Measure how long it takes to do the lazy compilation; only take the 941 // rest of the function into account to avoid overlap with the lazy 942 // parsing statistics. 943 HistogramTimerScope timer(isolate->counters()->compile_lazy()); 944 945 // After parsing we know the function's language mode. Remember it. 946 LanguageMode language_mode = info->function()->language_mode(); 947 info->SetLanguageMode(language_mode); 948 shared->set_language_mode(language_mode); 949 950 // Compile the code. 951 if (!MakeCode(info)) { 952 if (!isolate->has_pending_exception()) { 953 isolate->StackOverflow(); 954 } 955 } else { 956 InstallCodeCommon(info); 957 958 if (info->IsOptimizing()) { 959 Handle<Code> code = info->code(); 960 ASSERT(shared->scope_info() != ScopeInfo::Empty(isolate)); 961 info->closure()->ReplaceCode(*code); 962 InsertCodeIntoOptimizedCodeMap(info); 963 return true; 964 } else { 965 return InstallFullCode(info); 966 } 967 } 968 } 969 970 ASSERT(info->code().is_null()); 971 return false; 972 } 973 974 975 void Compiler::RecompileParallel(Handle<JSFunction> closure) { 976 ASSERT(closure->IsMarkedForParallelRecompilation()); 977 978 Isolate* isolate = closure->GetIsolate(); 979 // Here we prepare compile data for the parallel recompilation thread, but 980 // this still happens synchronously and interrupts execution. 981 Logger::TimerEventScope timer( 982 isolate, Logger::TimerEventScope::v8_recompile_synchronous); 983 984 if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) { 985 if (FLAG_trace_parallel_recompilation) { 986 PrintF(" ** Compilation queue full, will retry optimizing "); 987 closure->PrintName(); 988 PrintF(" on next run.\n"); 989 } 990 return; 991 } 992 993 SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(closure)); 994 VMState<COMPILER> state(isolate); 995 PostponeInterruptsScope postpone(isolate); 996 997 Handle<SharedFunctionInfo> shared = info->shared_info(); 998 int compiled_size = shared->end_position() - shared->start_position(); 999 isolate->counters()->total_compile_size()->Increment(compiled_size); 1000 info->SetOptimizing(BailoutId::None()); 1001 1002 { 1003 CompilationHandleScope handle_scope(*info); 1004 1005 if (InstallCodeFromOptimizedCodeMap(*info)) { 1006 return; 1007 } 1008 1009 if (Parser::Parse(*info)) { 1010 LanguageMode language_mode = info->function()->language_mode(); 1011 info->SetLanguageMode(language_mode); 1012 shared->set_language_mode(language_mode); 1013 info->SaveHandles(); 1014 1015 if (Rewriter::Rewrite(*info) && Scope::Analyze(*info)) { 1016 OptimizingCompiler* compiler = 1017 new(info->zone()) OptimizingCompiler(*info); 1018 OptimizingCompiler::Status status = compiler->CreateGraph(); 1019 if (status == OptimizingCompiler::SUCCEEDED) { 1020 info.Detach(); 1021 shared->code()->set_profiler_ticks(0); 1022 isolate->optimizing_compiler_thread()->QueueForOptimization(compiler); 1023 } else if (status == OptimizingCompiler::BAILED_OUT) { 1024 isolate->clear_pending_exception(); 1025 InstallFullCode(*info); 1026 } 1027 } 1028 } 1029 } 1030 1031 if (shared->code()->back_edges_patched_for_osr()) { 1032 // At this point we either put the function on recompilation queue or 1033 // aborted optimization. In either case we want to continue executing 1034 // the unoptimized code without running into OSR. If the unoptimized 1035 // code has been patched for OSR, unpatch it. 1036 InterruptStub interrupt_stub; 1037 Handle<Code> interrupt_code = interrupt_stub.GetCode(isolate); 1038 Handle<Code> replacement_code = 1039 isolate->builtins()->OnStackReplacement(); 1040 Deoptimizer::RevertInterruptCode(shared->code(), 1041 *interrupt_code, 1042 *replacement_code); 1043 } 1044 1045 if (isolate->has_pending_exception()) isolate->clear_pending_exception(); 1046 } 1047 1048 1049 void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) { 1050 SmartPointer<CompilationInfo> info(optimizing_compiler->info()); 1051 // The function may have already been optimized by OSR. Simply continue. 1052 // Except when OSR already disabled optimization for some reason. 1053 if (info->shared_info()->optimization_disabled()) { 1054 info->AbortOptimization(); 1055 InstallFullCode(*info); 1056 if (FLAG_trace_parallel_recompilation) { 1057 PrintF(" ** aborting optimization for "); 1058 info->closure()->PrintName(); 1059 PrintF(" as it has been disabled.\n"); 1060 } 1061 ASSERT(!info->closure()->IsMarkedForInstallingRecompiledCode()); 1062 return; 1063 } 1064 1065 Isolate* isolate = info->isolate(); 1066 VMState<COMPILER> state(isolate); 1067 Logger::TimerEventScope timer( 1068 isolate, Logger::TimerEventScope::v8_recompile_synchronous); 1069 // If crankshaft succeeded, install the optimized code else install 1070 // the unoptimized code. 1071 OptimizingCompiler::Status status = optimizing_compiler->last_status(); 1072 if (info->HasAbortedDueToDependencyChange()) { 1073 info->set_bailout_reason(kBailedOutDueToDependencyChange); 1074 status = optimizing_compiler->AbortOptimization(); 1075 } else if (status != OptimizingCompiler::SUCCEEDED) { 1076 info->set_bailout_reason(kFailedBailedOutLastTime); 1077 status = optimizing_compiler->AbortOptimization(); 1078 } else if (isolate->DebuggerHasBreakPoints()) { 1079 info->set_bailout_reason(kDebuggerIsActive); 1080 status = optimizing_compiler->AbortOptimization(); 1081 } else { 1082 status = optimizing_compiler->GenerateAndInstallCode(); 1083 ASSERT(status == OptimizingCompiler::SUCCEEDED || 1084 status == OptimizingCompiler::BAILED_OUT); 1085 } 1086 1087 InstallCodeCommon(*info); 1088 if (status == OptimizingCompiler::SUCCEEDED) { 1089 Handle<Code> code = info->code(); 1090 ASSERT(info->shared_info()->scope_info() != ScopeInfo::Empty(isolate)); 1091 info->closure()->ReplaceCode(*code); 1092 if (info->shared_info()->SearchOptimizedCodeMap( 1093 info->closure()->context()->native_context()) == -1) { 1094 InsertCodeIntoOptimizedCodeMap(*info); 1095 } 1096 if (FLAG_trace_parallel_recompilation) { 1097 PrintF(" ** Optimized code for "); 1098 info->closure()->PrintName(); 1099 PrintF(" installed.\n"); 1100 } 1101 } else { 1102 info->SetCode(Handle<Code>(info->shared_info()->code())); 1103 InstallFullCode(*info); 1104 } 1105 // Optimized code is finally replacing unoptimized code. Reset the latter's 1106 // profiler ticks to prevent too soon re-opt after a deopt. 1107 info->shared_info()->code()->set_profiler_ticks(0); 1108 ASSERT(!info->closure()->IsMarkedForInstallingRecompiledCode()); 1109 } 1110 1111 1112 Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, 1113 Handle<Script> script) { 1114 // Precondition: code has been parsed and scopes have been analyzed. 1115 CompilationInfoWithZone info(script); 1116 info.SetFunction(literal); 1117 info.SetScope(literal->scope()); 1118 info.SetLanguageMode(literal->scope()->language_mode()); 1119 1120 Isolate* isolate = info.isolate(); 1121 Factory* factory = isolate->factory(); 1122 LiveEditFunctionTracker live_edit_tracker(isolate, literal); 1123 // Determine if the function can be lazily compiled. This is necessary to 1124 // allow some of our builtin JS files to be lazily compiled. These 1125 // builtins cannot be handled lazily by the parser, since we have to know 1126 // if a function uses the special natives syntax, which is something the 1127 // parser records. 1128 // If the debugger requests compilation for break points, we cannot be 1129 // aggressive about lazy compilation, because it might trigger compilation 1130 // of functions without an outer context when setting a breakpoint through 1131 // Debug::FindSharedFunctionInfoInScript. 1132 bool allow_lazy_without_ctx = literal->AllowsLazyCompilationWithoutContext(); 1133 bool allow_lazy = literal->AllowsLazyCompilation() && 1134 !DebuggerWantsEagerCompilation(&info, allow_lazy_without_ctx); 1135 1136 Handle<ScopeInfo> scope_info(ScopeInfo::Empty(isolate)); 1137 1138 // Generate code 1139 if (FLAG_lazy && allow_lazy && !literal->is_parenthesized()) { 1140 Handle<Code> code = isolate->builtins()->LazyCompile(); 1141 info.SetCode(code); 1142 } else if (GenerateCode(&info)) { 1143 ASSERT(!info.code().is_null()); 1144 scope_info = ScopeInfo::Create(info.scope(), info.zone()); 1145 } else { 1146 return Handle<SharedFunctionInfo>::null(); 1147 } 1148 1149 // Create a shared function info object. 1150 Handle<SharedFunctionInfo> result = 1151 factory->NewSharedFunctionInfo(literal->name(), 1152 literal->materialized_literal_count(), 1153 literal->is_generator(), 1154 info.code(), 1155 scope_info); 1156 SetFunctionInfo(result, literal, false, script); 1157 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result); 1158 result->set_allows_lazy_compilation(allow_lazy); 1159 result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx); 1160 1161 // Set the expected number of properties for instances and return 1162 // the resulting function. 1163 SetExpectedNofPropertiesFromEstimate(result, 1164 literal->expected_property_count()); 1165 live_edit_tracker.RecordFunctionInfo(result, literal, info.zone()); 1166 return result; 1167 } 1168 1169 1170 // Sets the function info on a function. 1171 // The start_position points to the first '(' character after the function name 1172 // in the full script source. When counting characters in the script source the 1173 // the first character is number 0 (not 1). 1174 void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, 1175 FunctionLiteral* lit, 1176 bool is_toplevel, 1177 Handle<Script> script) { 1178 function_info->set_length(lit->parameter_count()); 1179 function_info->set_formal_parameter_count(lit->parameter_count()); 1180 function_info->set_script(*script); 1181 function_info->set_function_token_position(lit->function_token_position()); 1182 function_info->set_start_position(lit->start_position()); 1183 function_info->set_end_position(lit->end_position()); 1184 function_info->set_is_expression(lit->is_expression()); 1185 function_info->set_is_anonymous(lit->is_anonymous()); 1186 function_info->set_is_toplevel(is_toplevel); 1187 function_info->set_inferred_name(*lit->inferred_name()); 1188 function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); 1189 function_info->set_allows_lazy_compilation_without_context( 1190 lit->AllowsLazyCompilationWithoutContext()); 1191 function_info->set_language_mode(lit->language_mode()); 1192 function_info->set_uses_arguments(lit->scope()->arguments() != NULL); 1193 function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); 1194 function_info->set_ast_node_count(lit->ast_node_count()); 1195 function_info->set_is_function(lit->is_function()); 1196 function_info->set_dont_optimize(lit->flags()->Contains(kDontOptimize)); 1197 function_info->set_dont_inline(lit->flags()->Contains(kDontInline)); 1198 function_info->set_dont_cache(lit->flags()->Contains(kDontCache)); 1199 function_info->set_is_generator(lit->is_generator()); 1200 } 1201 1202 1203 void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, 1204 CompilationInfo* info, 1205 Handle<SharedFunctionInfo> shared) { 1206 // SharedFunctionInfo is passed separately, because if CompilationInfo 1207 // was created using Script object, it will not have it. 1208 1209 // Log the code generation. If source information is available include 1210 // script name and line number. Check explicitly whether logging is 1211 // enabled as finding the line number is not free. 1212 if (info->isolate()->logger()->is_logging_code_events() || 1213 info->isolate()->cpu_profiler()->is_profiling()) { 1214 Handle<Script> script = info->script(); 1215 Handle<Code> code = info->code(); 1216 if (*code == info->isolate()->builtins()->builtin(Builtins::kLazyCompile)) 1217 return; 1218 int line_num = GetScriptLineNumber(script, shared->start_position()) + 1; 1219 USE(line_num); 1220 if (script->name()->IsString()) { 1221 PROFILE(info->isolate(), 1222 CodeCreateEvent(Logger::ToNativeByScript(tag, *script), 1223 *code, 1224 *shared, 1225 info, 1226 String::cast(script->name()), 1227 line_num)); 1228 } else { 1229 PROFILE(info->isolate(), 1230 CodeCreateEvent(Logger::ToNativeByScript(tag, *script), 1231 *code, 1232 *shared, 1233 info, 1234 info->isolate()->heap()->empty_string(), 1235 line_num)); 1236 } 1237 } 1238 1239 GDBJIT(AddCode(Handle<String>(shared->DebugName()), 1240 Handle<Script>(info->script()), 1241 Handle<Code>(info->code()), 1242 info)); 1243 } 1244 1245 1246 CompilationPhase::CompilationPhase(const char* name, CompilationInfo* info) 1247 : name_(name), info_(info), zone_(info->isolate()) { 1248 if (FLAG_hydrogen_stats) { 1249 info_zone_start_allocation_size_ = info->zone()->allocation_size(); 1250 start_ticks_ = OS::Ticks(); 1251 } 1252 } 1253 1254 1255 CompilationPhase::~CompilationPhase() { 1256 if (FLAG_hydrogen_stats) { 1257 unsigned size = zone()->allocation_size(); 1258 size += info_->zone()->allocation_size() - info_zone_start_allocation_size_; 1259 int64_t ticks = OS::Ticks() - start_ticks_; 1260 isolate()->GetHStatistics()->SaveTiming(name_, ticks, size); 1261 } 1262 } 1263 1264 1265 bool CompilationPhase::ShouldProduceTraceOutput() const { 1266 // Trace if the appropriate trace flag is set and the phase name's first 1267 // character is in the FLAG_trace_phase command line parameter. 1268 bool tracing_on = info()->IsStub() ? 1269 FLAG_trace_hydrogen_stubs : 1270 FLAG_trace_hydrogen; 1271 return (tracing_on && 1272 OS::StrChr(const_cast<char*>(FLAG_trace_phase), name_[0]) != NULL); 1273 } 1274 1275 } } // namespace v8::internal 1276