1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/compiler.h" 6 7 #include <algorithm> 8 #include <memory> 9 10 #include "src/api-inl.h" 11 #include "src/asmjs/asm-js.h" 12 #include "src/assembler-inl.h" 13 #include "src/ast/prettyprinter.h" 14 #include "src/ast/scopes.h" 15 #include "src/base/optional.h" 16 #include "src/bootstrapper.h" 17 #include "src/compilation-cache.h" 18 #include "src/compiler-dispatcher/compiler-dispatcher.h" 19 #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" 20 #include "src/compiler/pipeline.h" 21 #include "src/debug/debug.h" 22 #include "src/debug/liveedit.h" 23 #include "src/frames-inl.h" 24 #include "src/globals.h" 25 #include "src/heap/heap.h" 26 #include "src/interpreter/interpreter.h" 27 #include "src/isolate-inl.h" 28 #include "src/log-inl.h" 29 #include "src/messages.h" 30 #include "src/objects/map.h" 31 #include "src/optimized-compilation-info.h" 32 #include "src/parsing/parse-info.h" 33 #include "src/parsing/parser.h" 34 #include "src/parsing/parsing.h" 35 #include "src/parsing/rewriter.h" 36 #include "src/parsing/scanner-character-streams.h" 37 #include "src/runtime-profiler.h" 38 #include "src/snapshot/code-serializer.h" 39 #include "src/unicode-cache.h" 40 #include "src/unoptimized-compilation-info.h" 41 #include "src/vm-state-inl.h" 42 43 namespace v8 { 44 namespace internal { 45 46 // A wrapper around a OptimizedCompilationInfo that detaches the Handles from 47 // the underlying DeferredHandleScope and stores them in info_ on 48 // destruction. 49 class CompilationHandleScope final { 50 public: 51 explicit CompilationHandleScope(Isolate* isolate, 52 OptimizedCompilationInfo* info) 53 : deferred_(isolate), info_(info) {} 54 ~CompilationHandleScope() { info_->set_deferred_handles(deferred_.Detach()); } 55 56 private: 57 DeferredHandleScope deferred_; 58 OptimizedCompilationInfo* info_; 59 }; 60 61 // Helper that times a scoped region and records the elapsed time. 62 struct ScopedTimer { 63 explicit ScopedTimer(base::TimeDelta* location) : location_(location) { 64 DCHECK_NOT_NULL(location_); 65 timer_.Start(); 66 } 67 68 ~ScopedTimer() { *location_ += timer_.Elapsed(); } 69 70 base::ElapsedTimer timer_; 71 base::TimeDelta* location_; 72 }; 73 74 namespace { 75 76 void LogFunctionCompilation(CodeEventListener::LogEventsAndTags tag, 77 Handle<SharedFunctionInfo> shared, 78 Handle<Script> script, 79 Handle<AbstractCode> abstract_code, bool optimizing, 80 double time_taken_ms, Isolate* isolate) { 81 DCHECK(!abstract_code.is_null()); 82 DCHECK(!abstract_code.is_identical_to(BUILTIN_CODE(isolate, CompileLazy))); 83 84 // Log the code generation. If source information is available include 85 // script name and line number. Check explicitly whether logging is 86 // enabled as finding the line number is not free. 87 if (!isolate->logger()->is_listening_to_code_events() && 88 !isolate->is_profiling() && !FLAG_log_function_events && 89 !isolate->code_event_dispatcher()->IsListeningToCodeEvents()) { 90 return; 91 } 92 93 int line_num = Script::GetLineNumber(script, shared->StartPosition()) + 1; 94 int column_num = Script::GetColumnNumber(script, shared->StartPosition()) + 1; 95 String* script_name = script->name()->IsString() 96 ? String::cast(script->name()) 97 : ReadOnlyRoots(isolate).empty_string(); 98 CodeEventListener::LogEventsAndTags log_tag = 99 Logger::ToNativeByScript(tag, *script); 100 PROFILE(isolate, CodeCreateEvent(log_tag, *abstract_code, *shared, 101 script_name, line_num, column_num)); 102 if (!FLAG_log_function_events) return; 103 104 DisallowHeapAllocation no_gc; 105 106 std::string name = optimizing ? "optimize" : "compile"; 107 switch (tag) { 108 case CodeEventListener::EVAL_TAG: 109 name += "-eval"; 110 break; 111 case CodeEventListener::SCRIPT_TAG: 112 break; 113 case CodeEventListener::LAZY_COMPILE_TAG: 114 name += "-lazy"; 115 break; 116 case CodeEventListener::FUNCTION_TAG: 117 break; 118 default: 119 UNREACHABLE(); 120 } 121 122 LOG(isolate, FunctionEvent(name.c_str(), script->id(), time_taken_ms, 123 shared->StartPosition(), shared->EndPosition(), 124 shared->DebugName())); 125 } 126 127 } // namespace 128 129 // ---------------------------------------------------------------------------- 130 // Implementation of UnoptimizedCompilationJob 131 132 CompilationJob::Status UnoptimizedCompilationJob::ExecuteJob() { 133 DisallowHeapAccess no_heap_access; 134 // Delegate to the underlying implementation. 135 DCHECK_EQ(state(), State::kReadyToExecute); 136 ScopedTimer t(&time_taken_to_execute_); 137 return UpdateState(ExecuteJobImpl(), State::kReadyToFinalize); 138 } 139 140 CompilationJob::Status UnoptimizedCompilationJob::FinalizeJob( 141 Handle<SharedFunctionInfo> shared_info, Isolate* isolate) { 142 DCHECK(ThreadId::Current().Equals(isolate->thread_id())); 143 DisallowCodeDependencyChange no_dependency_change; 144 DisallowJavascriptExecution no_js(isolate); 145 146 // Delegate to the underlying implementation. 147 DCHECK_EQ(state(), State::kReadyToFinalize); 148 ScopedTimer t(&time_taken_to_finalize_); 149 return UpdateState(FinalizeJobImpl(shared_info, isolate), State::kSucceeded); 150 } 151 152 void UnoptimizedCompilationJob::RecordCompilationStats(Isolate* isolate) const { 153 int code_size; 154 if (compilation_info()->has_bytecode_array()) { 155 code_size = compilation_info()->bytecode_array()->SizeIncludingMetadata(); 156 } else { 157 DCHECK(compilation_info()->has_asm_wasm_data()); 158 code_size = compilation_info()->asm_wasm_data()->Size(); 159 } 160 161 Counters* counters = isolate->counters(); 162 // TODO(4280): Rename counters from "baseline" to "unoptimized" eventually. 163 counters->total_baseline_code_size()->Increment(code_size); 164 counters->total_baseline_compile_count()->Increment(1); 165 166 // TODO(5203): Add timers for each phase of compilation. 167 } 168 169 void UnoptimizedCompilationJob::RecordFunctionCompilation( 170 CodeEventListener::LogEventsAndTags tag, Handle<SharedFunctionInfo> shared, 171 Isolate* isolate) const { 172 Handle<AbstractCode> abstract_code; 173 if (compilation_info()->has_bytecode_array()) { 174 abstract_code = 175 Handle<AbstractCode>::cast(compilation_info()->bytecode_array()); 176 } else { 177 DCHECK(compilation_info()->has_asm_wasm_data()); 178 abstract_code = 179 Handle<AbstractCode>::cast(BUILTIN_CODE(isolate, InstantiateAsmJs)); 180 } 181 182 double time_taken_ms = time_taken_to_execute_.InMillisecondsF() + 183 time_taken_to_finalize_.InMillisecondsF(); 184 185 LogFunctionCompilation(tag, shared, parse_info()->script(), abstract_code, 186 false, time_taken_ms, isolate); 187 } 188 189 // ---------------------------------------------------------------------------- 190 // Implementation of OptimizedCompilationJob 191 192 CompilationJob::Status OptimizedCompilationJob::PrepareJob(Isolate* isolate) { 193 DCHECK(ThreadId::Current().Equals(isolate->thread_id())); 194 DisallowJavascriptExecution no_js(isolate); 195 196 if (FLAG_trace_opt && compilation_info()->IsOptimizing()) { 197 StdoutStream os; 198 os << "[compiling method " << Brief(*compilation_info()->closure()) 199 << " using " << compiler_name_; 200 if (compilation_info()->is_osr()) os << " OSR"; 201 os << "]" << std::endl; 202 } 203 204 // Delegate to the underlying implementation. 205 DCHECK_EQ(state(), State::kReadyToPrepare); 206 ScopedTimer t(&time_taken_to_prepare_); 207 return UpdateState(PrepareJobImpl(isolate), State::kReadyToExecute); 208 } 209 210 CompilationJob::Status OptimizedCompilationJob::ExecuteJob() { 211 DisallowHeapAccess no_heap_access; 212 // Delegate to the underlying implementation. 213 DCHECK_EQ(state(), State::kReadyToExecute); 214 ScopedTimer t(&time_taken_to_execute_); 215 return UpdateState(ExecuteJobImpl(), State::kReadyToFinalize); 216 } 217 218 CompilationJob::Status OptimizedCompilationJob::FinalizeJob(Isolate* isolate) { 219 DCHECK(ThreadId::Current().Equals(isolate->thread_id())); 220 DisallowCodeDependencyChange no_dependency_change; 221 DisallowJavascriptExecution no_js(isolate); 222 223 // Delegate to the underlying implementation. 224 DCHECK_EQ(state(), State::kReadyToFinalize); 225 ScopedTimer t(&time_taken_to_finalize_); 226 return UpdateState(FinalizeJobImpl(isolate), State::kSucceeded); 227 } 228 229 CompilationJob::Status OptimizedCompilationJob::RetryOptimization( 230 BailoutReason reason) { 231 DCHECK(compilation_info_->IsOptimizing()); 232 compilation_info_->RetryOptimization(reason); 233 return UpdateState(FAILED, State::kFailed); 234 } 235 236 CompilationJob::Status OptimizedCompilationJob::AbortOptimization( 237 BailoutReason reason) { 238 DCHECK(compilation_info_->IsOptimizing()); 239 compilation_info_->AbortOptimization(reason); 240 return UpdateState(FAILED, State::kFailed); 241 } 242 243 void OptimizedCompilationJob::RecordCompilationStats() const { 244 DCHECK(compilation_info()->IsOptimizing()); 245 Handle<JSFunction> function = compilation_info()->closure(); 246 double ms_creategraph = time_taken_to_prepare_.InMillisecondsF(); 247 double ms_optimize = time_taken_to_execute_.InMillisecondsF(); 248 double ms_codegen = time_taken_to_finalize_.InMillisecondsF(); 249 if (FLAG_trace_opt) { 250 PrintF("[optimizing "); 251 function->ShortPrint(); 252 PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize, 253 ms_codegen); 254 } 255 if (FLAG_trace_opt_stats) { 256 static double compilation_time = 0.0; 257 static int compiled_functions = 0; 258 static int code_size = 0; 259 260 compilation_time += (ms_creategraph + ms_optimize + ms_codegen); 261 compiled_functions++; 262 code_size += function->shared()->SourceSize(); 263 PrintF("Compiled: %d functions with %d byte source size in %fms.\n", 264 compiled_functions, code_size, compilation_time); 265 } 266 } 267 268 void OptimizedCompilationJob::RecordFunctionCompilation( 269 CodeEventListener::LogEventsAndTags tag, Isolate* isolate) const { 270 Handle<AbstractCode> abstract_code = 271 Handle<AbstractCode>::cast(compilation_info()->code()); 272 273 double time_taken_ms = time_taken_to_prepare_.InMillisecondsF() + 274 time_taken_to_execute_.InMillisecondsF() + 275 time_taken_to_finalize_.InMillisecondsF(); 276 277 Handle<Script> script( 278 Script::cast(compilation_info()->shared_info()->script()), isolate); 279 LogFunctionCompilation(tag, compilation_info()->shared_info(), script, 280 abstract_code, true, time_taken_ms, isolate); 281 } 282 283 // ---------------------------------------------------------------------------- 284 // Local helper methods that make up the compilation pipeline. 285 286 namespace { 287 288 bool UseAsmWasm(FunctionLiteral* literal, bool asm_wasm_broken) { 289 // Check whether asm.js validation is enabled. 290 if (!FLAG_validate_asm) return false; 291 292 // Modules that have validated successfully, but were subsequently broken by 293 // invalid module instantiation attempts are off limit forever. 294 if (asm_wasm_broken) return false; 295 296 // In stress mode we want to run the validator on everything. 297 if (FLAG_stress_validate_asm) return true; 298 299 // In general, we respect the "use asm" directive. 300 return literal->scope()->IsAsmModule(); 301 } 302 303 void InstallBytecodeArray(Handle<BytecodeArray> bytecode_array, 304 Handle<SharedFunctionInfo> shared_info, 305 ParseInfo* parse_info, Isolate* isolate) { 306 if (!FLAG_interpreted_frames_native_stack) { 307 shared_info->set_bytecode_array(*bytecode_array); 308 return; 309 } 310 311 Handle<Code> code; 312 { 313 CodeSpaceMemoryModificationScope code_allocation(isolate->heap()); 314 315 code = isolate->factory()->CopyCode( 316 BUILTIN_CODE(isolate, InterpreterEntryTrampoline)); 317 } 318 319 Handle<InterpreterData> interpreter_data = Handle<InterpreterData>::cast( 320 isolate->factory()->NewStruct(INTERPRETER_DATA_TYPE, TENURED)); 321 322 interpreter_data->set_bytecode_array(*bytecode_array); 323 interpreter_data->set_interpreter_trampoline(*code); 324 325 shared_info->set_interpreter_data(*interpreter_data); 326 327 Handle<Script> script = parse_info->script(); 328 Handle<AbstractCode> abstract_code = Handle<AbstractCode>::cast(code); 329 int line_num = 330 Script::GetLineNumber(script, shared_info->StartPosition()) + 1; 331 int column_num = 332 Script::GetColumnNumber(script, shared_info->StartPosition()) + 1; 333 String* script_name = script->name()->IsString() 334 ? String::cast(script->name()) 335 : ReadOnlyRoots(isolate).empty_string(); 336 CodeEventListener::LogEventsAndTags log_tag = Logger::ToNativeByScript( 337 CodeEventListener::INTERPRETED_FUNCTION_TAG, *script); 338 PROFILE(isolate, CodeCreateEvent(log_tag, *abstract_code, *shared_info, 339 script_name, line_num, column_num)); 340 } 341 342 void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info, 343 Handle<SharedFunctionInfo> shared_info, 344 ParseInfo* parse_info, Isolate* isolate) { 345 DCHECK_EQ(shared_info->language_mode(), 346 compilation_info->literal()->language_mode()); 347 348 // Update the shared function info with the scope info. 349 Handle<ScopeInfo> scope_info = compilation_info->scope()->scope_info(); 350 shared_info->set_scope_info(*scope_info); 351 352 if (compilation_info->has_bytecode_array()) { 353 DCHECK(!shared_info->HasBytecodeArray()); // Only compiled once. 354 DCHECK(!compilation_info->has_asm_wasm_data()); 355 DCHECK(!shared_info->HasFeedbackMetadata()); 356 357 Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New( 358 isolate, compilation_info->feedback_vector_spec()); 359 360 InstallBytecodeArray(compilation_info->bytecode_array(), shared_info, 361 parse_info, isolate); 362 shared_info->set_feedback_metadata(*feedback_metadata); 363 } else { 364 DCHECK(compilation_info->has_asm_wasm_data()); 365 shared_info->set_asm_wasm_data(*compilation_info->asm_wasm_data()); 366 shared_info->set_feedback_metadata( 367 ReadOnlyRoots(isolate).empty_feedback_metadata()); 368 } 369 370 // Install coverage info on the shared function info. 371 if (compilation_info->has_coverage_info()) { 372 DCHECK(isolate->is_block_code_coverage()); 373 isolate->debug()->InstallCoverageInfo(shared_info, 374 compilation_info->coverage_info()); 375 } 376 } 377 378 void EnsureSharedFunctionInfosArrayOnScript(ParseInfo* parse_info, 379 Isolate* isolate) { 380 DCHECK(parse_info->is_toplevel()); 381 DCHECK(!parse_info->script().is_null()); 382 if (parse_info->script()->shared_function_infos()->length() > 0) { 383 DCHECK_EQ(parse_info->script()->shared_function_infos()->length(), 384 parse_info->max_function_literal_id() + 1); 385 return; 386 } 387 Handle<WeakFixedArray> infos(isolate->factory()->NewWeakFixedArray( 388 parse_info->max_function_literal_id() + 1)); 389 parse_info->script()->set_shared_function_infos(*infos); 390 } 391 392 void SetSharedFunctionFlagsFromLiteral(FunctionLiteral* literal, 393 Handle<SharedFunctionInfo> shared_info) { 394 // Don't overwrite values set by the bootstrapper. 395 if (!shared_info->HasLength()) { 396 shared_info->set_length(literal->function_length()); 397 } 398 shared_info->set_has_duplicate_parameters( 399 literal->has_duplicate_parameters()); 400 shared_info->SetExpectedNofPropertiesFromEstimate(literal); 401 if (literal->dont_optimize_reason() != BailoutReason::kNoReason) { 402 shared_info->DisableOptimization(literal->dont_optimize_reason()); 403 } 404 } 405 406 CompilationJob::Status FinalizeUnoptimizedCompilationJob( 407 UnoptimizedCompilationJob* job, Handle<SharedFunctionInfo> shared_info, 408 Isolate* isolate) { 409 UnoptimizedCompilationInfo* compilation_info = job->compilation_info(); 410 ParseInfo* parse_info = job->parse_info(); 411 412 SetSharedFunctionFlagsFromLiteral(compilation_info->literal(), shared_info); 413 414 CompilationJob::Status status = job->FinalizeJob(shared_info, isolate); 415 if (status == CompilationJob::SUCCEEDED) { 416 InstallUnoptimizedCode(compilation_info, shared_info, parse_info, isolate); 417 CodeEventListener::LogEventsAndTags log_tag; 418 if (parse_info->is_toplevel()) { 419 log_tag = compilation_info->is_eval() ? CodeEventListener::EVAL_TAG 420 : CodeEventListener::SCRIPT_TAG; 421 } else { 422 log_tag = parse_info->lazy_compile() ? CodeEventListener::LAZY_COMPILE_TAG 423 : CodeEventListener::FUNCTION_TAG; 424 } 425 job->RecordFunctionCompilation(log_tag, shared_info, isolate); 426 job->RecordCompilationStats(isolate); 427 } 428 return status; 429 } 430 431 std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs( 432 ParseInfo* parse_info, FunctionLiteral* literal, 433 AccountingAllocator* allocator, 434 UnoptimizedCompilationJobList* inner_function_jobs) { 435 if (UseAsmWasm(literal, parse_info->is_asm_wasm_broken())) { 436 std::unique_ptr<UnoptimizedCompilationJob> asm_job( 437 AsmJs::NewCompilationJob(parse_info, literal, allocator)); 438 if (asm_job->ExecuteJob() == CompilationJob::SUCCEEDED) { 439 return asm_job; 440 } 441 // asm.js validation failed, fall through to standard unoptimized compile. 442 // Note: we rely on the fact that AsmJs jobs have done all validation in the 443 // PrepareJob and ExecuteJob phases and can't fail in FinalizeJob with 444 // with a validation error or another error that could be solve by falling 445 // through to standard unoptimized compile. 446 } 447 ZoneVector<FunctionLiteral*> eager_inner_literals(0, parse_info->zone()); 448 std::unique_ptr<UnoptimizedCompilationJob> job( 449 interpreter::Interpreter::NewCompilationJob( 450 parse_info, literal, allocator, &eager_inner_literals)); 451 452 if (job->ExecuteJob() != CompilationJob::SUCCEEDED) { 453 // Compilation failed, return null. 454 return std::unique_ptr<UnoptimizedCompilationJob>(); 455 } 456 457 // Recursively compile eager inner literals. 458 for (FunctionLiteral* inner_literal : eager_inner_literals) { 459 std::unique_ptr<UnoptimizedCompilationJob> inner_job( 460 ExecuteUnoptimizedCompileJobs(parse_info, inner_literal, allocator, 461 inner_function_jobs)); 462 // Compilation failed, return null. 463 if (!inner_job) return std::unique_ptr<UnoptimizedCompilationJob>(); 464 inner_function_jobs->emplace_front(std::move(inner_job)); 465 } 466 467 return job; 468 } 469 470 std::unique_ptr<UnoptimizedCompilationJob> GenerateUnoptimizedCode( 471 ParseInfo* parse_info, AccountingAllocator* allocator, 472 UnoptimizedCompilationJobList* inner_function_jobs) { 473 DisallowHeapAccess no_heap_access; 474 DCHECK(inner_function_jobs->empty()); 475 476 if (!Compiler::Analyze(parse_info)) { 477 return std::unique_ptr<UnoptimizedCompilationJob>(); 478 } 479 480 // Prepare and execute compilation of the outer-most function. 481 std::unique_ptr<UnoptimizedCompilationJob> outer_function_job( 482 ExecuteUnoptimizedCompileJobs(parse_info, parse_info->literal(), 483 allocator, inner_function_jobs)); 484 if (!outer_function_job) return std::unique_ptr<UnoptimizedCompilationJob>(); 485 486 // Character stream shouldn't be used again. 487 parse_info->ResetCharacterStream(); 488 489 return outer_function_job; 490 } 491 492 bool FinalizeUnoptimizedCode( 493 ParseInfo* parse_info, Isolate* isolate, 494 Handle<SharedFunctionInfo> shared_info, 495 UnoptimizedCompilationJob* outer_function_job, 496 UnoptimizedCompilationJobList* inner_function_jobs) { 497 DCHECK(AllowCompilation::IsAllowed(isolate)); 498 499 // Allocate scope infos for the literal. 500 DeclarationScope::AllocateScopeInfos(parse_info, isolate); 501 502 // Finalize the outer-most function's compilation job. 503 if (FinalizeUnoptimizedCompilationJob(outer_function_job, shared_info, 504 isolate) != CompilationJob::SUCCEEDED) { 505 return false; 506 } 507 508 // Finalize the inner functions' compilation jobs. 509 for (auto&& inner_job : *inner_function_jobs) { 510 Handle<SharedFunctionInfo> inner_shared_info = 511 Compiler::GetSharedFunctionInfo( 512 inner_job->compilation_info()->literal(), parse_info->script(), 513 isolate); 514 // The inner function might be compiled already if compiling for debug. 515 // TODO(rmcilroy): Fix this and DCHECK !is_compiled() once Full-Codegen dies 516 if (inner_shared_info->is_compiled()) continue; 517 if (FinalizeUnoptimizedCompilationJob(inner_job.get(), inner_shared_info, 518 isolate) != 519 CompilationJob::SUCCEEDED) { 520 return false; 521 } 522 } 523 524 // Report any warnings generated during compilation. 525 if (parse_info->pending_error_handler()->has_pending_warnings()) { 526 parse_info->pending_error_handler()->ReportWarnings(isolate, 527 parse_info->script()); 528 } 529 530 return true; 531 } 532 533 V8_WARN_UNUSED_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeCache( 534 Handle<JSFunction> function, BailoutId osr_offset) { 535 RuntimeCallTimerScope runtimeTimer( 536 function->GetIsolate(), 537 RuntimeCallCounterId::kCompileGetFromOptimizedCodeMap); 538 Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate()); 539 DisallowHeapAllocation no_gc; 540 if (osr_offset.IsNone()) { 541 if (function->feedback_cell()->value()->IsFeedbackVector()) { 542 FeedbackVector* feedback_vector = function->feedback_vector(); 543 feedback_vector->EvictOptimizedCodeMarkedForDeoptimization( 544 function->shared(), "GetCodeFromOptimizedCodeCache"); 545 Code* code = feedback_vector->optimized_code(); 546 547 if (code != nullptr) { 548 // Caching of optimized code enabled and optimized code found. 549 DCHECK(!code->marked_for_deoptimization()); 550 DCHECK(function->shared()->is_compiled()); 551 return Handle<Code>(code, feedback_vector->GetIsolate()); 552 } 553 } 554 } 555 return MaybeHandle<Code>(); 556 } 557 558 void ClearOptimizedCodeCache(OptimizedCompilationInfo* compilation_info) { 559 Handle<JSFunction> function = compilation_info->closure(); 560 if (compilation_info->osr_offset().IsNone()) { 561 Handle<FeedbackVector> vector = 562 handle(function->feedback_vector(), function->GetIsolate()); 563 vector->ClearOptimizationMarker(); 564 } 565 } 566 567 void InsertCodeIntoOptimizedCodeCache( 568 OptimizedCompilationInfo* compilation_info) { 569 Handle<Code> code = compilation_info->code(); 570 if (code->kind() != Code::OPTIMIZED_FUNCTION) return; // Nothing to do. 571 572 // Function context specialization folds-in the function context, 573 // so no sharing can occur. 574 if (compilation_info->is_function_context_specializing()) { 575 // Native context specialized code is not shared, so make sure the optimized 576 // code cache is clear. 577 ClearOptimizedCodeCache(compilation_info); 578 return; 579 } 580 581 // Cache optimized context-specific code. 582 Handle<JSFunction> function = compilation_info->closure(); 583 Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate()); 584 Handle<Context> native_context(function->context()->native_context(), 585 function->GetIsolate()); 586 if (compilation_info->osr_offset().IsNone()) { 587 Handle<FeedbackVector> vector = 588 handle(function->feedback_vector(), function->GetIsolate()); 589 FeedbackVector::SetOptimizedCode(vector, code); 590 } 591 } 592 593 bool GetOptimizedCodeNow(OptimizedCompilationJob* job, Isolate* isolate) { 594 TimerEventScope<TimerEventRecompileSynchronous> timer(isolate); 595 RuntimeCallTimerScope runtimeTimer( 596 isolate, RuntimeCallCounterId::kRecompileSynchronous); 597 OptimizedCompilationInfo* compilation_info = job->compilation_info(); 598 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 599 "V8.RecompileSynchronous"); 600 601 if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED || 602 job->ExecuteJob() != CompilationJob::SUCCEEDED || 603 job->FinalizeJob(isolate) != CompilationJob::SUCCEEDED) { 604 if (FLAG_trace_opt) { 605 PrintF("[aborted optimizing "); 606 compilation_info->closure()->ShortPrint(); 607 PrintF(" because: %s]\n", 608 GetBailoutReason(compilation_info->bailout_reason())); 609 } 610 return false; 611 } 612 613 // Success! 614 job->RecordCompilationStats(); 615 DCHECK(!isolate->has_pending_exception()); 616 InsertCodeIntoOptimizedCodeCache(compilation_info); 617 job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, isolate); 618 return true; 619 } 620 621 bool GetOptimizedCodeLater(OptimizedCompilationJob* job, Isolate* isolate) { 622 OptimizedCompilationInfo* compilation_info = job->compilation_info(); 623 if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) { 624 if (FLAG_trace_concurrent_recompilation) { 625 PrintF(" ** Compilation queue full, will retry optimizing "); 626 compilation_info->closure()->ShortPrint(); 627 PrintF(" later.\n"); 628 } 629 return false; 630 } 631 632 if (isolate->heap()->HighMemoryPressure()) { 633 if (FLAG_trace_concurrent_recompilation) { 634 PrintF(" ** High memory pressure, will retry optimizing "); 635 compilation_info->closure()->ShortPrint(); 636 PrintF(" later.\n"); 637 } 638 return false; 639 } 640 641 TimerEventScope<TimerEventRecompileSynchronous> timer(isolate); 642 RuntimeCallTimerScope runtimeTimer( 643 isolate, RuntimeCallCounterId::kRecompileSynchronous); 644 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 645 "V8.RecompileSynchronous"); 646 647 if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED) return false; 648 isolate->optimizing_compile_dispatcher()->QueueForOptimization(job); 649 650 if (FLAG_trace_concurrent_recompilation) { 651 PrintF(" ** Queued "); 652 compilation_info->closure()->ShortPrint(); 653 PrintF(" for concurrent optimization.\n"); 654 } 655 return true; 656 } 657 658 MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, 659 ConcurrencyMode mode, 660 BailoutId osr_offset = BailoutId::None(), 661 JavaScriptFrame* osr_frame = nullptr) { 662 Isolate* isolate = function->GetIsolate(); 663 Handle<SharedFunctionInfo> shared(function->shared(), isolate); 664 665 // Make sure we clear the optimization marker on the function so that we 666 // don't try to re-optimize. 667 if (function->HasOptimizationMarker()) { 668 function->ClearOptimizationMarker(); 669 } 670 671 if (isolate->debug()->needs_check_on_function_call()) { 672 // Do not optimize when debugger needs to hook into every call. 673 return MaybeHandle<Code>(); 674 } 675 676 Handle<Code> cached_code; 677 if (GetCodeFromOptimizedCodeCache(function, osr_offset) 678 .ToHandle(&cached_code)) { 679 if (FLAG_trace_opt) { 680 PrintF("[found optimized code for "); 681 function->ShortPrint(); 682 if (!osr_offset.IsNone()) { 683 PrintF(" at OSR AST id %d", osr_offset.ToInt()); 684 } 685 PrintF("]\n"); 686 } 687 return cached_code; 688 } 689 690 // Reset profiler ticks, function is no longer considered hot. 691 DCHECK(shared->is_compiled()); 692 function->feedback_vector()->set_profiler_ticks(0); 693 694 VMState<COMPILER> state(isolate); 695 DCHECK(!isolate->has_pending_exception()); 696 PostponeInterruptsScope postpone(isolate); 697 bool has_script = shared->script()->IsScript(); 698 // BUG(5946): This DCHECK is necessary to make certain that we won't 699 // tolerate the lack of a script without bytecode. 700 DCHECK_IMPLIES(!has_script, shared->HasBytecodeArray()); 701 std::unique_ptr<OptimizedCompilationJob> job( 702 compiler::Pipeline::NewCompilationJob(isolate, function, has_script)); 703 OptimizedCompilationInfo* compilation_info = job->compilation_info(); 704 705 compilation_info->SetOptimizingForOsr(osr_offset, osr_frame); 706 707 // Do not use TurboFan if we need to be able to set break points. 708 if (compilation_info->shared_info()->HasBreakInfo()) { 709 compilation_info->AbortOptimization(BailoutReason::kFunctionBeingDebugged); 710 return MaybeHandle<Code>(); 711 } 712 713 // Do not use TurboFan when %NeverOptimizeFunction was applied. 714 if (shared->optimization_disabled() && 715 shared->disable_optimization_reason() == 716 BailoutReason::kOptimizationDisabledForTest) { 717 compilation_info->AbortOptimization( 718 BailoutReason::kOptimizationDisabledForTest); 719 return MaybeHandle<Code>(); 720 } 721 722 // Do not use TurboFan if optimization is disabled or function doesn't pass 723 // turbo_filter. 724 if (!FLAG_opt || !shared->PassesFilter(FLAG_turbo_filter)) { 725 compilation_info->AbortOptimization(BailoutReason::kOptimizationDisabled); 726 return MaybeHandle<Code>(); 727 } 728 729 TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate); 730 RuntimeCallTimerScope runtimeTimer(isolate, 731 RuntimeCallCounterId::kOptimizeCode); 732 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.OptimizeCode"); 733 734 // In case of concurrent recompilation, all handles below this point will be 735 // allocated in a deferred handle scope that is detached and handed off to 736 // the background thread when we return. 737 base::Optional<CompilationHandleScope> compilation; 738 if (mode == ConcurrencyMode::kConcurrent) { 739 compilation.emplace(isolate, compilation_info); 740 } 741 742 // All handles below will be canonicalized. 743 CanonicalHandleScope canonical(isolate); 744 745 // Reopen handles in the new CompilationHandleScope. 746 compilation_info->ReopenHandlesInNewHandleScope(isolate); 747 748 if (mode == ConcurrencyMode::kConcurrent) { 749 if (GetOptimizedCodeLater(job.get(), isolate)) { 750 job.release(); // The background recompile job owns this now. 751 752 // Set the optimization marker and return a code object which checks it. 753 function->SetOptimizationMarker(OptimizationMarker::kInOptimizationQueue); 754 DCHECK(function->IsInterpreted() || 755 (!function->is_compiled() && function->shared()->IsInterpreted())); 756 DCHECK(function->shared()->HasBytecodeArray()); 757 return BUILTIN_CODE(isolate, InterpreterEntryTrampoline); 758 } 759 } else { 760 if (GetOptimizedCodeNow(job.get(), isolate)) 761 return compilation_info->code(); 762 } 763 764 if (isolate->has_pending_exception()) isolate->clear_pending_exception(); 765 return MaybeHandle<Code>(); 766 } 767 768 CompilationJob::Status FinalizeOptimizedCompilationJob( 769 OptimizedCompilationJob* job, Isolate* isolate) { 770 OptimizedCompilationInfo* compilation_info = job->compilation_info(); 771 772 TimerEventScope<TimerEventRecompileSynchronous> timer(isolate); 773 RuntimeCallTimerScope runtimeTimer( 774 isolate, RuntimeCallCounterId::kRecompileSynchronous); 775 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 776 "V8.RecompileSynchronous"); 777 778 Handle<SharedFunctionInfo> shared = compilation_info->shared_info(); 779 780 // Reset profiler ticks, function is no longer considered hot. 781 compilation_info->closure()->feedback_vector()->set_profiler_ticks(0); 782 783 DCHECK(!shared->HasBreakInfo()); 784 785 // 1) Optimization on the concurrent thread may have failed. 786 // 2) The function may have already been optimized by OSR. Simply continue. 787 // Except when OSR already disabled optimization for some reason. 788 // 3) The code may have already been invalidated due to dependency change. 789 // 4) Code generation may have failed. 790 if (job->state() == CompilationJob::State::kReadyToFinalize) { 791 if (shared->optimization_disabled()) { 792 job->RetryOptimization(BailoutReason::kOptimizationDisabled); 793 } else if (job->FinalizeJob(isolate) == CompilationJob::SUCCEEDED) { 794 job->RecordCompilationStats(); 795 job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, 796 isolate); 797 InsertCodeIntoOptimizedCodeCache(compilation_info); 798 if (FLAG_trace_opt) { 799 PrintF("[completed optimizing "); 800 compilation_info->closure()->ShortPrint(); 801 PrintF("]\n"); 802 } 803 compilation_info->closure()->set_code(*compilation_info->code()); 804 return CompilationJob::SUCCEEDED; 805 } 806 } 807 808 DCHECK_EQ(job->state(), CompilationJob::State::kFailed); 809 if (FLAG_trace_opt) { 810 PrintF("[aborted optimizing "); 811 compilation_info->closure()->ShortPrint(); 812 PrintF(" because: %s]\n", 813 GetBailoutReason(compilation_info->bailout_reason())); 814 } 815 compilation_info->closure()->set_code(shared->GetCode()); 816 // Clear the InOptimizationQueue marker, if it exists. 817 if (compilation_info->closure()->IsInOptimizationQueue()) { 818 compilation_info->closure()->ClearOptimizationMarker(); 819 } 820 return CompilationJob::FAILED; 821 } 822 823 bool FailWithPendingException(Isolate* isolate, ParseInfo* parse_info, 824 Compiler::ClearExceptionFlag flag) { 825 if (flag == Compiler::CLEAR_EXCEPTION) { 826 isolate->clear_pending_exception(); 827 } else if (!isolate->has_pending_exception()) { 828 if (parse_info->pending_error_handler()->has_pending_error()) { 829 parse_info->pending_error_handler()->ReportErrors( 830 isolate, parse_info->script(), parse_info->ast_value_factory()); 831 } else { 832 isolate->StackOverflow(); 833 } 834 } 835 return false; 836 } 837 838 MaybeHandle<SharedFunctionInfo> FinalizeTopLevel( 839 ParseInfo* parse_info, Isolate* isolate, 840 UnoptimizedCompilationJob* outer_function_job, 841 UnoptimizedCompilationJobList* inner_function_jobs) { 842 Handle<Script> script = parse_info->script(); 843 844 // Internalize ast values onto the heap. 845 parse_info->ast_value_factory()->Internalize(isolate); 846 847 // Create shared function infos for top level and shared function infos array 848 // for inner functions. 849 EnsureSharedFunctionInfosArrayOnScript(parse_info, isolate); 850 DCHECK_EQ(kNoSourcePosition, 851 parse_info->literal()->function_token_position()); 852 Handle<SharedFunctionInfo> shared_info = 853 isolate->factory()->NewSharedFunctionInfoForLiteral( 854 parse_info->literal(), parse_info->script(), true); 855 856 // Finalize compilation of the unoptimized bytecode or asm-js data. 857 if (!FinalizeUnoptimizedCode(parse_info, isolate, shared_info, 858 outer_function_job, inner_function_jobs)) { 859 FailWithPendingException(isolate, parse_info, 860 Compiler::ClearExceptionFlag::KEEP_EXCEPTION); 861 return MaybeHandle<SharedFunctionInfo>(); 862 } 863 864 if (!script.is_null()) { 865 script->set_compilation_state(Script::COMPILATION_STATE_COMPILED); 866 } 867 868 return shared_info; 869 } 870 871 MaybeHandle<SharedFunctionInfo> CompileToplevel(ParseInfo* parse_info, 872 Isolate* isolate) { 873 TimerEventScope<TimerEventCompileCode> top_level_timer(isolate); 874 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode"); 875 DCHECK(ThreadId::Current().Equals(isolate->thread_id())); 876 877 PostponeInterruptsScope postpone(isolate); 878 DCHECK(!isolate->native_context().is_null()); 879 RuntimeCallTimerScope runtimeTimer( 880 isolate, parse_info->is_eval() ? RuntimeCallCounterId::kCompileEval 881 : RuntimeCallCounterId::kCompileScript); 882 VMState<BYTECODE_COMPILER> state(isolate); 883 if (parse_info->literal() == nullptr && 884 !parsing::ParseProgram(parse_info, isolate)) { 885 return MaybeHandle<SharedFunctionInfo>(); 886 } 887 // Measure how long it takes to do the compilation; only take the 888 // rest of the function into account to avoid overlap with the 889 // parsing statistics. 890 HistogramTimer* rate = parse_info->is_eval() 891 ? isolate->counters()->compile_eval() 892 : isolate->counters()->compile(); 893 HistogramTimerScope timer(rate); 894 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 895 parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile"); 896 897 // Generate the unoptimized bytecode or asm-js data. 898 UnoptimizedCompilationJobList inner_function_jobs; 899 std::unique_ptr<UnoptimizedCompilationJob> outer_function_job( 900 GenerateUnoptimizedCode(parse_info, isolate->allocator(), 901 &inner_function_jobs)); 902 if (!outer_function_job) { 903 FailWithPendingException(isolate, parse_info, 904 Compiler::ClearExceptionFlag::KEEP_EXCEPTION); 905 return MaybeHandle<SharedFunctionInfo>(); 906 } 907 908 return FinalizeTopLevel(parse_info, isolate, outer_function_job.get(), 909 &inner_function_jobs); 910 } 911 912 std::unique_ptr<UnoptimizedCompilationJob> CompileTopLevelOnBackgroundThread( 913 ParseInfo* parse_info, AccountingAllocator* allocator, 914 UnoptimizedCompilationJobList* inner_function_jobs) { 915 DisallowHeapAccess no_heap_access; 916 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 917 "V8.CompileCodeBackground"); 918 RuntimeCallTimerScope runtimeTimer( 919 parse_info->runtime_call_stats(), 920 parse_info->is_eval() ? RuntimeCallCounterId::kCompileBackgroundEval 921 : RuntimeCallCounterId::kCompileBackgroundScript); 922 923 LanguageMode language_mode = construct_language_mode(FLAG_use_strict); 924 parse_info->set_language_mode( 925 stricter_language_mode(parse_info->language_mode(), language_mode)); 926 927 // Can't access scope info data off-main-thread. 928 DCHECK(!parse_info->consumed_preparsed_scope_data()->HasData()); 929 930 // Generate the unoptimized bytecode or asm-js data. 931 std::unique_ptr<UnoptimizedCompilationJob> outer_function_job( 932 GenerateUnoptimizedCode(parse_info, allocator, inner_function_jobs)); 933 return outer_function_job; 934 } 935 936 class BackgroundCompileTask : public ScriptCompiler::ScriptStreamingTask { 937 public: 938 BackgroundCompileTask(ScriptStreamingData* source, Isolate* isolate); 939 940 virtual void Run(); 941 942 private: 943 ScriptStreamingData* source_; // Not owned. 944 int stack_size_; 945 AccountingAllocator* allocator_; 946 TimedHistogram* timer_; 947 948 DISALLOW_COPY_AND_ASSIGN(BackgroundCompileTask); 949 }; 950 951 BackgroundCompileTask::BackgroundCompileTask(ScriptStreamingData* source, 952 Isolate* isolate) 953 : source_(source), 954 stack_size_(i::FLAG_stack_size), 955 timer_(isolate->counters()->compile_script_on_background()) { 956 VMState<PARSER> state(isolate); 957 958 // Prepare the data for the internalization phase and compilation phase, which 959 // will happen in the main thread after parsing. 960 ParseInfo* info = new ParseInfo(isolate); 961 LOG(isolate, ScriptEvent(Logger::ScriptEventType::kStreamingCompile, 962 info->script_id())); 963 if (V8_UNLIKELY(FLAG_runtime_stats)) { 964 info->set_runtime_call_stats(new (info->zone()) RuntimeCallStats()); 965 } else { 966 info->set_runtime_call_stats(nullptr); 967 } 968 info->set_toplevel(); 969 std::unique_ptr<Utf16CharacterStream> stream( 970 ScannerStream::For(source->source_stream.get(), source->encoding, 971 info->runtime_call_stats())); 972 info->set_character_stream(std::move(stream)); 973 info->set_unicode_cache(&source_->unicode_cache); 974 info->set_allow_lazy_parsing(); 975 if (V8_UNLIKELY(info->block_coverage_enabled())) { 976 info->AllocateSourceRangeMap(); 977 } 978 LanguageMode language_mode = construct_language_mode(FLAG_use_strict); 979 info->set_language_mode( 980 stricter_language_mode(info->language_mode(), language_mode)); 981 982 source->info.reset(info); 983 allocator_ = isolate->allocator(); 984 985 // Parser needs to stay alive for finalizing the parsing on the main 986 // thread. 987 source_->parser.reset(new Parser(source_->info.get())); 988 source_->parser->DeserializeScopeChain(isolate, source_->info.get(), 989 MaybeHandle<ScopeInfo>()); 990 } 991 992 void BackgroundCompileTask::Run() { 993 TimedHistogramScope timer(timer_); 994 DisallowHeapAccess no_heap_access; 995 996 source_->info->set_on_background_thread(true); 997 998 // Reset the stack limit of the parser to reflect correctly that we're on a 999 // background thread. 1000 uintptr_t old_stack_limit = source_->info->stack_limit(); 1001 uintptr_t stack_limit = GetCurrentStackPosition() - stack_size_ * KB; 1002 source_->info->set_stack_limit(stack_limit); 1003 source_->parser->set_stack_limit(stack_limit); 1004 1005 source_->parser->ParseOnBackground(source_->info.get()); 1006 if (source_->info->literal() != nullptr) { 1007 // Parsing has succeeded, compile. 1008 source_->outer_function_job = CompileTopLevelOnBackgroundThread( 1009 source_->info.get(), allocator_, &source_->inner_function_jobs); 1010 } 1011 1012 source_->info->EmitBackgroundParseStatisticsOnBackgroundThread(); 1013 1014 source_->info->set_on_background_thread(false); 1015 source_->info->set_stack_limit(old_stack_limit); 1016 } 1017 1018 } // namespace 1019 1020 // ---------------------------------------------------------------------------- 1021 // Implementation of Compiler 1022 1023 bool Compiler::Analyze(ParseInfo* parse_info) { 1024 DCHECK_NOT_NULL(parse_info->literal()); 1025 RuntimeCallTimerScope runtimeTimer( 1026 parse_info->runtime_call_stats(), 1027 parse_info->on_background_thread() 1028 ? RuntimeCallCounterId::kCompileBackgroundAnalyse 1029 : RuntimeCallCounterId::kCompileAnalyse); 1030 if (!Rewriter::Rewrite(parse_info)) return false; 1031 if (!DeclarationScope::Analyze(parse_info)) return false; 1032 return true; 1033 } 1034 1035 bool Compiler::ParseAndAnalyze(ParseInfo* parse_info, 1036 Handle<SharedFunctionInfo> shared_info, 1037 Isolate* isolate) { 1038 if (!parsing::ParseAny(parse_info, shared_info, isolate)) { 1039 return false; 1040 } 1041 return Compiler::Analyze(parse_info); 1042 } 1043 1044 bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info, 1045 ClearExceptionFlag flag) { 1046 // We should never reach here if the function is already compiled. 1047 DCHECK(!shared_info->is_compiled()); 1048 1049 Isolate* isolate = shared_info->GetIsolate(); 1050 DCHECK(AllowCompilation::IsAllowed(isolate)); 1051 DCHECK(ThreadId::Current().Equals(isolate->thread_id())); 1052 DCHECK(!isolate->has_pending_exception()); 1053 DCHECK(!shared_info->HasBytecodeArray()); 1054 VMState<BYTECODE_COMPILER> state(isolate); 1055 PostponeInterruptsScope postpone(isolate); 1056 TimerEventScope<TimerEventCompileCode> compile_timer(isolate); 1057 RuntimeCallTimerScope runtimeTimer(isolate, 1058 RuntimeCallCounterId::kCompileFunction); 1059 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode"); 1060 AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy()); 1061 1062 // Set up parse info. 1063 ParseInfo parse_info(isolate, shared_info); 1064 parse_info.set_lazy_compile(); 1065 1066 // Check if the compiler dispatcher has shared_info enqueued for compile. 1067 CompilerDispatcher* dispatcher = isolate->compiler_dispatcher(); 1068 if (dispatcher->IsEnqueued(shared_info)) { 1069 if (!dispatcher->FinishNow(shared_info)) { 1070 return FailWithPendingException(isolate, &parse_info, flag); 1071 } 1072 return true; 1073 } 1074 1075 if (FLAG_preparser_scope_analysis) { 1076 if (shared_info->HasUncompiledDataWithPreParsedScope()) { 1077 parse_info.consumed_preparsed_scope_data()->SetData( 1078 isolate, handle(shared_info->uncompiled_data_with_pre_parsed_scope() 1079 ->pre_parsed_scope_data(), 1080 isolate)); 1081 } 1082 } 1083 1084 // Parse and update ParseInfo with the results. 1085 if (!parsing::ParseFunction(&parse_info, shared_info, isolate)) { 1086 return FailWithPendingException(isolate, &parse_info, flag); 1087 } 1088 1089 // Generate the unoptimized bytecode or asm-js data. 1090 UnoptimizedCompilationJobList inner_function_jobs; 1091 std::unique_ptr<UnoptimizedCompilationJob> outer_function_job( 1092 GenerateUnoptimizedCode(&parse_info, isolate->allocator(), 1093 &inner_function_jobs)); 1094 if (!outer_function_job) { 1095 return FailWithPendingException(isolate, &parse_info, flag); 1096 } 1097 1098 // Internalize ast values onto the heap. 1099 parse_info.ast_value_factory()->Internalize(isolate); 1100 1101 // Finalize compilation of the unoptimized bytecode or asm-js data. 1102 if (!FinalizeUnoptimizedCode(&parse_info, isolate, shared_info, 1103 outer_function_job.get(), 1104 &inner_function_jobs)) { 1105 return FailWithPendingException(isolate, &parse_info, flag); 1106 } 1107 1108 DCHECK(!isolate->has_pending_exception()); 1109 return true; 1110 } 1111 1112 bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) { 1113 // We should never reach here if the function is already compiled or optimized 1114 DCHECK(!function->is_compiled()); 1115 DCHECK(!function->IsOptimized()); 1116 DCHECK(!function->HasOptimizationMarker()); 1117 DCHECK(!function->HasOptimizedCode()); 1118 1119 Isolate* isolate = function->GetIsolate(); 1120 Handle<SharedFunctionInfo> shared_info = handle(function->shared(), isolate); 1121 1122 // Ensure shared function info is compiled. 1123 if (!shared_info->is_compiled() && !Compile(shared_info, flag)) return false; 1124 Handle<Code> code = handle(shared_info->GetCode(), isolate); 1125 1126 // Allocate FeedbackVector for the JSFunction. 1127 JSFunction::EnsureFeedbackVector(function); 1128 1129 // Optimize now if --always-opt is enabled. 1130 if (FLAG_always_opt && !function->shared()->HasAsmWasmData()) { 1131 if (FLAG_trace_opt) { 1132 PrintF("[optimizing "); 1133 function->ShortPrint(); 1134 PrintF(" because --always-opt]\n"); 1135 } 1136 Handle<Code> opt_code; 1137 if (GetOptimizedCode(function, ConcurrencyMode::kNotConcurrent) 1138 .ToHandle(&opt_code)) { 1139 code = opt_code; 1140 } 1141 } 1142 1143 // Install code on closure. 1144 function->set_code(*code); 1145 1146 // Check postconditions on success. 1147 DCHECK(!isolate->has_pending_exception()); 1148 DCHECK(function->shared()->is_compiled()); 1149 DCHECK(function->is_compiled()); 1150 return true; 1151 } 1152 1153 bool Compiler::CompileOptimized(Handle<JSFunction> function, 1154 ConcurrencyMode mode) { 1155 if (function->IsOptimized()) return true; 1156 Isolate* isolate = function->GetIsolate(); 1157 DCHECK(AllowCompilation::IsAllowed(isolate)); 1158 1159 // Start a compilation. 1160 Handle<Code> code; 1161 if (!GetOptimizedCode(function, mode).ToHandle(&code)) { 1162 // Optimization failed, get unoptimized code. Unoptimized code must exist 1163 // already if we are optimizing. 1164 DCHECK(!isolate->has_pending_exception()); 1165 DCHECK(function->shared()->is_compiled()); 1166 DCHECK(function->shared()->IsInterpreted()); 1167 code = BUILTIN_CODE(isolate, InterpreterEntryTrampoline); 1168 } 1169 1170 // Install code on closure. 1171 function->set_code(*code); 1172 1173 // Check postconditions on success. 1174 DCHECK(!isolate->has_pending_exception()); 1175 DCHECK(function->shared()->is_compiled()); 1176 DCHECK(function->is_compiled()); 1177 DCHECK_IMPLIES(function->HasOptimizationMarker(), 1178 function->IsInOptimizationQueue()); 1179 DCHECK_IMPLIES(function->HasOptimizationMarker(), 1180 function->ChecksOptimizationMarker()); 1181 DCHECK_IMPLIES(function->IsInOptimizationQueue(), 1182 mode == ConcurrencyMode::kConcurrent); 1183 return true; 1184 } 1185 1186 MaybeHandle<SharedFunctionInfo> Compiler::CompileForLiveEdit( 1187 ParseInfo* parse_info, Isolate* isolate) { 1188 return CompileToplevel(parse_info, isolate); 1189 } 1190 1191 MaybeHandle<JSFunction> Compiler::GetFunctionFromEval( 1192 Handle<String> source, Handle<SharedFunctionInfo> outer_info, 1193 Handle<Context> context, LanguageMode language_mode, 1194 ParseRestriction restriction, int parameters_end_pos, 1195 int eval_scope_position, int eval_position, int line_offset, 1196 int column_offset, Handle<Object> script_name, 1197 ScriptOriginOptions options) { 1198 Isolate* isolate = context->GetIsolate(); 1199 int source_length = source->length(); 1200 isolate->counters()->total_eval_size()->Increment(source_length); 1201 isolate->counters()->total_compile_size()->Increment(source_length); 1202 1203 // The cache lookup key needs to be aware of the separation between the 1204 // parameters and the body to prevent this valid invocation: 1205 // Function("", "function anonymous(\n/**/) {\n}"); 1206 // from adding an entry that falsely approves this invalid invocation: 1207 // Function("\n/**/) {\nfunction anonymous(", "}"); 1208 // The actual eval_scope_position for indirect eval and CreateDynamicFunction 1209 // is unused (just 0), which means it's an available field to use to indicate 1210 // this separation. But to make sure we're not causing other false hits, we 1211 // negate the scope position. 1212 if (FLAG_harmony_function_tostring && 1213 restriction == ONLY_SINGLE_FUNCTION_LITERAL && 1214 parameters_end_pos != kNoSourcePosition) { 1215 // use the parameters_end_pos as the eval_scope_position in the eval cache. 1216 DCHECK_EQ(eval_scope_position, 0); 1217 eval_scope_position = -parameters_end_pos; 1218 } 1219 CompilationCache* compilation_cache = isolate->compilation_cache(); 1220 InfoCellPair eval_result = compilation_cache->LookupEval( 1221 source, outer_info, context, language_mode, eval_scope_position); 1222 Handle<FeedbackCell> feedback_cell; 1223 if (eval_result.has_feedback_cell()) { 1224 feedback_cell = handle(eval_result.feedback_cell(), isolate); 1225 } 1226 1227 Handle<SharedFunctionInfo> shared_info; 1228 Handle<Script> script; 1229 bool allow_eval_cache; 1230 if (eval_result.has_shared()) { 1231 shared_info = Handle<SharedFunctionInfo>(eval_result.shared(), isolate); 1232 script = Handle<Script>(Script::cast(shared_info->script()), isolate); 1233 allow_eval_cache = true; 1234 } else { 1235 ParseInfo parse_info(isolate); 1236 script = parse_info.CreateScript(isolate, source, options); 1237 if (!script_name.is_null()) { 1238 // TODO(cbruni): check whether we can store this data in options 1239 script->set_name(*script_name); 1240 script->set_line_offset(line_offset); 1241 script->set_column_offset(column_offset); 1242 LOG(isolate, ScriptDetails(*script)); 1243 } 1244 script->set_compilation_type(Script::COMPILATION_TYPE_EVAL); 1245 script->set_eval_from_shared(*outer_info); 1246 if (eval_position == kNoSourcePosition) { 1247 // If the position is missing, attempt to get the code offset by 1248 // walking the stack. Do not translate the code offset into source 1249 // position, but store it as negative value for lazy translation. 1250 StackTraceFrameIterator it(isolate); 1251 if (!it.done() && it.is_javascript()) { 1252 FrameSummary summary = FrameSummary::GetTop(it.javascript_frame()); 1253 script->set_eval_from_shared( 1254 summary.AsJavaScript().function()->shared()); 1255 eval_position = -summary.code_offset(); 1256 } else { 1257 eval_position = 0; 1258 } 1259 } 1260 script->set_eval_from_position(eval_position); 1261 1262 parse_info.set_eval(); 1263 parse_info.set_language_mode(language_mode); 1264 parse_info.set_parse_restriction(restriction); 1265 parse_info.set_parameters_end_pos(parameters_end_pos); 1266 if (!context->IsNativeContext()) { 1267 parse_info.set_outer_scope_info(handle(context->scope_info(), isolate)); 1268 } 1269 DCHECK(!parse_info.is_module()); 1270 1271 if (!CompileToplevel(&parse_info, isolate).ToHandle(&shared_info)) { 1272 return MaybeHandle<JSFunction>(); 1273 } 1274 allow_eval_cache = parse_info.allow_eval_cache(); 1275 } 1276 1277 // If caller is strict mode, the result must be in strict mode as well. 1278 DCHECK(is_sloppy(language_mode) || is_strict(shared_info->language_mode())); 1279 1280 Handle<JSFunction> result; 1281 if (eval_result.has_shared()) { 1282 if (eval_result.has_feedback_cell()) { 1283 result = isolate->factory()->NewFunctionFromSharedFunctionInfo( 1284 shared_info, context, feedback_cell, NOT_TENURED); 1285 } else { 1286 result = isolate->factory()->NewFunctionFromSharedFunctionInfo( 1287 shared_info, context, NOT_TENURED); 1288 JSFunction::EnsureFeedbackVector(result); 1289 if (allow_eval_cache) { 1290 // Make sure to cache this result. 1291 Handle<FeedbackCell> new_feedback_cell(result->feedback_cell(), 1292 isolate); 1293 compilation_cache->PutEval(source, outer_info, context, shared_info, 1294 new_feedback_cell, eval_scope_position); 1295 } 1296 } 1297 } else { 1298 result = isolate->factory()->NewFunctionFromSharedFunctionInfo( 1299 shared_info, context, NOT_TENURED); 1300 JSFunction::EnsureFeedbackVector(result); 1301 if (allow_eval_cache) { 1302 // Add the SharedFunctionInfo and the LiteralsArray to the eval cache if 1303 // we didn't retrieve from there. 1304 Handle<FeedbackCell> new_feedback_cell(result->feedback_cell(), isolate); 1305 compilation_cache->PutEval(source, outer_info, context, shared_info, 1306 new_feedback_cell, eval_scope_position); 1307 } 1308 } 1309 1310 return result; 1311 } 1312 1313 1314 bool Compiler::CodeGenerationFromStringsAllowed(Isolate* isolate, 1315 Handle<Context> context, 1316 Handle<String> source) { 1317 DCHECK(context->allow_code_gen_from_strings()->IsFalse(isolate)); 1318 // Check with callback if set. 1319 AllowCodeGenerationFromStringsCallback callback = 1320 isolate->allow_code_gen_callback(); 1321 if (callback == nullptr) { 1322 // No callback set and code generation disallowed. 1323 return false; 1324 } else { 1325 // Callback set. Let it decide if code generation is allowed. 1326 VMState<EXTERNAL> state(isolate); 1327 return callback(v8::Utils::ToLocal(context), v8::Utils::ToLocal(source)); 1328 } 1329 } 1330 1331 MaybeHandle<JSFunction> Compiler::GetFunctionFromString( 1332 Handle<Context> context, Handle<String> source, 1333 ParseRestriction restriction, int parameters_end_pos) { 1334 Isolate* const isolate = context->GetIsolate(); 1335 Handle<Context> native_context(context->native_context(), isolate); 1336 1337 // Check if native context allows code generation from 1338 // strings. Throw an exception if it doesn't. 1339 if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) && 1340 !CodeGenerationFromStringsAllowed(isolate, native_context, source)) { 1341 Handle<Object> error_message = 1342 native_context->ErrorMessageForCodeGenerationFromStrings(); 1343 THROW_NEW_ERROR(isolate, NewEvalError(MessageTemplate::kCodeGenFromStrings, 1344 error_message), 1345 JSFunction); 1346 } 1347 1348 // Compile source string in the native context. 1349 int eval_scope_position = 0; 1350 int eval_position = kNoSourcePosition; 1351 Handle<SharedFunctionInfo> outer_info( 1352 native_context->empty_function()->shared(), isolate); 1353 return Compiler::GetFunctionFromEval( 1354 source, outer_info, native_context, LanguageMode::kSloppy, restriction, 1355 parameters_end_pos, eval_scope_position, eval_position); 1356 } 1357 1358 namespace { 1359 1360 struct ScriptCompileTimerScope { 1361 public: 1362 // TODO(leszeks): There are too many blink-specific entries in this enum, 1363 // figure out a way to push produce/hit-isolate-cache/consume/consume-failed 1364 // back up the API and log them in blink instead. 1365 enum class CacheBehaviour { 1366 kProduceCodeCache, 1367 kHitIsolateCacheWhenNoCache, 1368 kConsumeCodeCache, 1369 kConsumeCodeCacheFailed, 1370 kNoCacheBecauseInlineScript, 1371 kNoCacheBecauseScriptTooSmall, 1372 kNoCacheBecauseCacheTooCold, 1373 kNoCacheNoReason, 1374 kNoCacheBecauseNoResource, 1375 kNoCacheBecauseInspector, 1376 kNoCacheBecauseCachingDisabled, 1377 kNoCacheBecauseModule, 1378 kNoCacheBecauseStreamingSource, 1379 kNoCacheBecauseV8Extension, 1380 kHitIsolateCacheWhenProduceCodeCache, 1381 kHitIsolateCacheWhenConsumeCodeCache, 1382 kNoCacheBecauseExtensionModule, 1383 kNoCacheBecausePacScript, 1384 kNoCacheBecauseInDocumentWrite, 1385 kNoCacheBecauseResourceWithNoCacheHandler, 1386 kHitIsolateCacheWhenStreamingSource, 1387 kCount 1388 }; 1389 1390 explicit ScriptCompileTimerScope( 1391 Isolate* isolate, ScriptCompiler::NoCacheReason no_cache_reason) 1392 : isolate_(isolate), 1393 all_scripts_histogram_scope_(isolate->counters()->compile_script(), 1394 true), 1395 no_cache_reason_(no_cache_reason), 1396 hit_isolate_cache_(false), 1397 producing_code_cache_(false), 1398 consuming_code_cache_(false), 1399 consuming_code_cache_failed_(false) {} 1400 1401 ~ScriptCompileTimerScope() { 1402 CacheBehaviour cache_behaviour = GetCacheBehaviour(); 1403 1404 Histogram* cache_behaviour_histogram = 1405 isolate_->counters()->compile_script_cache_behaviour(); 1406 // Sanity check that the histogram has exactly one bin per enum entry. 1407 DCHECK_EQ(0, cache_behaviour_histogram->min()); 1408 DCHECK_EQ(static_cast<int>(CacheBehaviour::kCount), 1409 cache_behaviour_histogram->max() + 1); 1410 DCHECK_EQ(static_cast<int>(CacheBehaviour::kCount), 1411 cache_behaviour_histogram->num_buckets()); 1412 cache_behaviour_histogram->AddSample(static_cast<int>(cache_behaviour)); 1413 1414 histogram_scope_.set_histogram( 1415 GetCacheBehaviourTimedHistogram(cache_behaviour)); 1416 } 1417 1418 void set_hit_isolate_cache() { hit_isolate_cache_ = true; } 1419 1420 void set_producing_code_cache() { producing_code_cache_ = true; } 1421 1422 void set_consuming_code_cache() { consuming_code_cache_ = true; } 1423 1424 void set_consuming_code_cache_failed() { 1425 consuming_code_cache_failed_ = true; 1426 } 1427 1428 private: 1429 Isolate* isolate_; 1430 LazyTimedHistogramScope histogram_scope_; 1431 // TODO(leszeks): This timer is the sum of the other times, consider removing 1432 // it to save space. 1433 HistogramTimerScope all_scripts_histogram_scope_; 1434 ScriptCompiler::NoCacheReason no_cache_reason_; 1435 bool hit_isolate_cache_; 1436 bool producing_code_cache_; 1437 bool consuming_code_cache_; 1438 bool consuming_code_cache_failed_; 1439 1440 CacheBehaviour GetCacheBehaviour() { 1441 if (producing_code_cache_) { 1442 if (hit_isolate_cache_) { 1443 return CacheBehaviour::kHitIsolateCacheWhenProduceCodeCache; 1444 } else { 1445 return CacheBehaviour::kProduceCodeCache; 1446 } 1447 } 1448 1449 if (consuming_code_cache_) { 1450 if (hit_isolate_cache_) { 1451 return CacheBehaviour::kHitIsolateCacheWhenConsumeCodeCache; 1452 } else if (consuming_code_cache_failed_) { 1453 return CacheBehaviour::kConsumeCodeCacheFailed; 1454 } 1455 return CacheBehaviour::kConsumeCodeCache; 1456 } 1457 1458 if (hit_isolate_cache_) { 1459 if (no_cache_reason_ == ScriptCompiler::kNoCacheBecauseStreamingSource) { 1460 return CacheBehaviour::kHitIsolateCacheWhenStreamingSource; 1461 } 1462 return CacheBehaviour::kHitIsolateCacheWhenNoCache; 1463 } 1464 1465 switch (no_cache_reason_) { 1466 case ScriptCompiler::kNoCacheBecauseInlineScript: 1467 return CacheBehaviour::kNoCacheBecauseInlineScript; 1468 case ScriptCompiler::kNoCacheBecauseScriptTooSmall: 1469 return CacheBehaviour::kNoCacheBecauseScriptTooSmall; 1470 case ScriptCompiler::kNoCacheBecauseCacheTooCold: 1471 return CacheBehaviour::kNoCacheBecauseCacheTooCold; 1472 case ScriptCompiler::kNoCacheNoReason: 1473 return CacheBehaviour::kNoCacheNoReason; 1474 case ScriptCompiler::kNoCacheBecauseNoResource: 1475 return CacheBehaviour::kNoCacheBecauseNoResource; 1476 case ScriptCompiler::kNoCacheBecauseInspector: 1477 return CacheBehaviour::kNoCacheBecauseInspector; 1478 case ScriptCompiler::kNoCacheBecauseCachingDisabled: 1479 return CacheBehaviour::kNoCacheBecauseCachingDisabled; 1480 case ScriptCompiler::kNoCacheBecauseModule: 1481 return CacheBehaviour::kNoCacheBecauseModule; 1482 case ScriptCompiler::kNoCacheBecauseStreamingSource: 1483 return CacheBehaviour::kNoCacheBecauseStreamingSource; 1484 case ScriptCompiler::kNoCacheBecauseV8Extension: 1485 return CacheBehaviour::kNoCacheBecauseV8Extension; 1486 case ScriptCompiler::kNoCacheBecauseExtensionModule: 1487 return CacheBehaviour::kNoCacheBecauseExtensionModule; 1488 case ScriptCompiler::kNoCacheBecausePacScript: 1489 return CacheBehaviour::kNoCacheBecausePacScript; 1490 case ScriptCompiler::kNoCacheBecauseInDocumentWrite: 1491 return CacheBehaviour::kNoCacheBecauseInDocumentWrite; 1492 case ScriptCompiler::kNoCacheBecauseResourceWithNoCacheHandler: 1493 return CacheBehaviour::kNoCacheBecauseResourceWithNoCacheHandler; 1494 case ScriptCompiler::kNoCacheBecauseDeferredProduceCodeCache: { 1495 if (hit_isolate_cache_) { 1496 return CacheBehaviour::kHitIsolateCacheWhenProduceCodeCache; 1497 } else { 1498 return CacheBehaviour::kProduceCodeCache; 1499 } 1500 } 1501 } 1502 UNREACHABLE(); 1503 } 1504 1505 TimedHistogram* GetCacheBehaviourTimedHistogram( 1506 CacheBehaviour cache_behaviour) { 1507 switch (cache_behaviour) { 1508 case CacheBehaviour::kProduceCodeCache: 1509 // Even if we hit the isolate's compilation cache, we currently recompile 1510 // when we want to produce the code cache. 1511 case CacheBehaviour::kHitIsolateCacheWhenProduceCodeCache: 1512 return isolate_->counters()->compile_script_with_produce_cache(); 1513 case CacheBehaviour::kHitIsolateCacheWhenNoCache: 1514 case CacheBehaviour::kHitIsolateCacheWhenConsumeCodeCache: 1515 case CacheBehaviour::kHitIsolateCacheWhenStreamingSource: 1516 return isolate_->counters()->compile_script_with_isolate_cache_hit(); 1517 case CacheBehaviour::kConsumeCodeCacheFailed: 1518 return isolate_->counters()->compile_script_consume_failed(); 1519 case CacheBehaviour::kConsumeCodeCache: 1520 return isolate_->counters()->compile_script_with_consume_cache(); 1521 1522 case CacheBehaviour::kNoCacheBecauseInlineScript: 1523 return isolate_->counters() 1524 ->compile_script_no_cache_because_inline_script(); 1525 case CacheBehaviour::kNoCacheBecauseScriptTooSmall: 1526 return isolate_->counters() 1527 ->compile_script_no_cache_because_script_too_small(); 1528 case CacheBehaviour::kNoCacheBecauseCacheTooCold: 1529 return isolate_->counters() 1530 ->compile_script_no_cache_because_cache_too_cold(); 1531 1532 // Aggregate all the other "no cache" counters into a single histogram, to 1533 // save space. 1534 case CacheBehaviour::kNoCacheNoReason: 1535 case CacheBehaviour::kNoCacheBecauseNoResource: 1536 case CacheBehaviour::kNoCacheBecauseInspector: 1537 case CacheBehaviour::kNoCacheBecauseCachingDisabled: 1538 // TODO(leszeks): Consider counting separately once modules are more 1539 // common. 1540 case CacheBehaviour::kNoCacheBecauseModule: 1541 // TODO(leszeks): Count separately or remove entirely once we have 1542 // background compilation. 1543 case CacheBehaviour::kNoCacheBecauseStreamingSource: 1544 case CacheBehaviour::kNoCacheBecauseV8Extension: 1545 case CacheBehaviour::kNoCacheBecauseExtensionModule: 1546 case CacheBehaviour::kNoCacheBecausePacScript: 1547 case CacheBehaviour::kNoCacheBecauseInDocumentWrite: 1548 case CacheBehaviour::kNoCacheBecauseResourceWithNoCacheHandler: 1549 return isolate_->counters()->compile_script_no_cache_other(); 1550 1551 case CacheBehaviour::kCount: 1552 UNREACHABLE(); 1553 } 1554 UNREACHABLE(); 1555 } 1556 }; 1557 1558 Handle<Script> NewScript(Isolate* isolate, ParseInfo* parse_info, 1559 Handle<String> source, 1560 Compiler::ScriptDetails script_details, 1561 ScriptOriginOptions origin_options, 1562 NativesFlag natives) { 1563 // Create a script object describing the script to be compiled. 1564 Handle<Script> script = 1565 parse_info->CreateScript(isolate, source, origin_options, natives); 1566 Handle<Object> script_name; 1567 if (script_details.name_obj.ToHandle(&script_name)) { 1568 script->set_name(*script_name); 1569 script->set_line_offset(script_details.line_offset); 1570 script->set_column_offset(script_details.column_offset); 1571 } 1572 Handle<Object> source_map_url; 1573 if (script_details.source_map_url.ToHandle(&source_map_url)) { 1574 script->set_source_mapping_url(*source_map_url); 1575 } 1576 Handle<FixedArray> host_defined_options; 1577 if (script_details.host_defined_options.ToHandle(&host_defined_options)) { 1578 script->set_host_defined_options(*host_defined_options); 1579 } 1580 LOG(isolate, ScriptDetails(*script)); 1581 return script; 1582 } 1583 1584 } // namespace 1585 1586 MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript( 1587 Isolate* isolate, Handle<String> source, 1588 const Compiler::ScriptDetails& script_details, 1589 ScriptOriginOptions origin_options, v8::Extension* extension, 1590 ScriptData* cached_data, ScriptCompiler::CompileOptions compile_options, 1591 ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) { 1592 ScriptCompileTimerScope compile_timer(isolate, no_cache_reason); 1593 1594 if (compile_options == ScriptCompiler::kNoCompileOptions || 1595 compile_options == ScriptCompiler::kEagerCompile) { 1596 DCHECK_NULL(cached_data); 1597 } else { 1598 DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache); 1599 DCHECK(cached_data); 1600 DCHECK_NULL(extension); 1601 } 1602 int source_length = source->length(); 1603 isolate->counters()->total_load_size()->Increment(source_length); 1604 isolate->counters()->total_compile_size()->Increment(source_length); 1605 1606 LanguageMode language_mode = construct_language_mode(FLAG_use_strict); 1607 CompilationCache* compilation_cache = isolate->compilation_cache(); 1608 1609 // Do a lookup in the compilation cache but not for extensions. 1610 MaybeHandle<SharedFunctionInfo> maybe_result; 1611 if (extension == nullptr) { 1612 bool can_consume_code_cache = 1613 compile_options == ScriptCompiler::kConsumeCodeCache; 1614 if (can_consume_code_cache) { 1615 compile_timer.set_consuming_code_cache(); 1616 } 1617 1618 // First check per-isolate compilation cache. 1619 maybe_result = compilation_cache->LookupScript( 1620 source, script_details.name_obj, script_details.line_offset, 1621 script_details.column_offset, origin_options, isolate->native_context(), 1622 language_mode); 1623 if (!maybe_result.is_null()) { 1624 compile_timer.set_hit_isolate_cache(); 1625 } else if (can_consume_code_cache) { 1626 compile_timer.set_consuming_code_cache(); 1627 // Then check cached code provided by embedder. 1628 HistogramTimerScope timer(isolate->counters()->compile_deserialize()); 1629 RuntimeCallTimerScope runtimeTimer( 1630 isolate, RuntimeCallCounterId::kCompileDeserialize); 1631 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 1632 "V8.CompileDeserialize"); 1633 Handle<SharedFunctionInfo> inner_result; 1634 if (CodeSerializer::Deserialize(isolate, cached_data, source, 1635 origin_options) 1636 .ToHandle(&inner_result)) { 1637 // Promote to per-isolate compilation cache. 1638 DCHECK(inner_result->is_compiled()); 1639 compilation_cache->PutScript(source, isolate->native_context(), 1640 language_mode, inner_result); 1641 Handle<Script> script(Script::cast(inner_result->script()), isolate); 1642 maybe_result = inner_result; 1643 } else { 1644 // Deserializer failed. Fall through to compile. 1645 compile_timer.set_consuming_code_cache_failed(); 1646 } 1647 } 1648 } 1649 1650 if (maybe_result.is_null()) { 1651 ParseInfo parse_info(isolate); 1652 // No cache entry found compile the script. 1653 NewScript(isolate, &parse_info, source, script_details, origin_options, 1654 natives); 1655 1656 // Compile the function and add it to the isolate cache. 1657 if (origin_options.IsModule()) parse_info.set_module(); 1658 parse_info.set_extension(extension); 1659 parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile); 1660 1661 parse_info.set_language_mode( 1662 stricter_language_mode(parse_info.language_mode(), language_mode)); 1663 maybe_result = CompileToplevel(&parse_info, isolate); 1664 Handle<SharedFunctionInfo> result; 1665 if (extension == nullptr && maybe_result.ToHandle(&result)) { 1666 DCHECK(result->is_compiled()); 1667 compilation_cache->PutScript(source, isolate->native_context(), 1668 language_mode, result); 1669 } else if (maybe_result.is_null() && natives != EXTENSION_CODE && 1670 natives != NATIVES_CODE) { 1671 isolate->ReportPendingMessages(); 1672 } 1673 } 1674 1675 return maybe_result; 1676 } 1677 1678 MaybeHandle<JSFunction> Compiler::GetWrappedFunction( 1679 Handle<String> source, Handle<FixedArray> arguments, 1680 Handle<Context> context, const Compiler::ScriptDetails& script_details, 1681 ScriptOriginOptions origin_options, ScriptData* cached_data, 1682 v8::ScriptCompiler::CompileOptions compile_options, 1683 v8::ScriptCompiler::NoCacheReason no_cache_reason) { 1684 Isolate* isolate = context->GetIsolate(); 1685 ScriptCompileTimerScope compile_timer(isolate, no_cache_reason); 1686 1687 if (compile_options == ScriptCompiler::kNoCompileOptions || 1688 compile_options == ScriptCompiler::kEagerCompile) { 1689 DCHECK_NULL(cached_data); 1690 } else { 1691 DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache); 1692 DCHECK(cached_data); 1693 } 1694 1695 int source_length = source->length(); 1696 isolate->counters()->total_compile_size()->Increment(source_length); 1697 1698 LanguageMode language_mode = construct_language_mode(FLAG_use_strict); 1699 1700 MaybeHandle<SharedFunctionInfo> maybe_result; 1701 bool can_consume_code_cache = 1702 compile_options == ScriptCompiler::kConsumeCodeCache; 1703 if (can_consume_code_cache) { 1704 compile_timer.set_consuming_code_cache(); 1705 // Then check cached code provided by embedder. 1706 HistogramTimerScope timer(isolate->counters()->compile_deserialize()); 1707 RuntimeCallTimerScope runtimeTimer( 1708 isolate, RuntimeCallCounterId::kCompileDeserialize); 1709 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 1710 "V8.CompileDeserialize"); 1711 maybe_result = CodeSerializer::Deserialize(isolate, cached_data, source, 1712 origin_options); 1713 if (maybe_result.is_null()) { 1714 // Deserializer failed. Fall through to compile. 1715 compile_timer.set_consuming_code_cache_failed(); 1716 } 1717 } 1718 1719 Handle<SharedFunctionInfo> wrapped; 1720 Handle<Script> script; 1721 if (!maybe_result.ToHandle(&wrapped)) { 1722 ParseInfo parse_info(isolate); 1723 script = NewScript(isolate, &parse_info, source, script_details, 1724 origin_options, NOT_NATIVES_CODE); 1725 script->set_wrapped_arguments(*arguments); 1726 1727 parse_info.set_eval(); // Use an eval scope as declaration scope. 1728 parse_info.set_wrapped_as_function(); 1729 // parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile); 1730 if (!context->IsNativeContext()) { 1731 parse_info.set_outer_scope_info(handle(context->scope_info(), isolate)); 1732 } 1733 parse_info.set_language_mode( 1734 stricter_language_mode(parse_info.language_mode(), language_mode)); 1735 1736 Handle<SharedFunctionInfo> top_level; 1737 maybe_result = CompileToplevel(&parse_info, isolate); 1738 if (maybe_result.is_null()) isolate->ReportPendingMessages(); 1739 ASSIGN_RETURN_ON_EXCEPTION(isolate, top_level, maybe_result, JSFunction); 1740 1741 SharedFunctionInfo::ScriptIterator infos(isolate, *script); 1742 while (SharedFunctionInfo* info = infos.Next()) { 1743 if (info->is_wrapped()) { 1744 wrapped = Handle<SharedFunctionInfo>(info, isolate); 1745 break; 1746 } 1747 } 1748 DCHECK(!wrapped.is_null()); 1749 } else { 1750 script = Handle<Script>(Script::cast(wrapped->script()), isolate); 1751 } 1752 1753 return isolate->factory()->NewFunctionFromSharedFunctionInfo(wrapped, context, 1754 NOT_TENURED); 1755 } 1756 1757 ScriptCompiler::ScriptStreamingTask* Compiler::NewBackgroundCompileTask( 1758 ScriptStreamingData* source, Isolate* isolate) { 1759 return new BackgroundCompileTask(source, isolate); 1760 } 1761 1762 MaybeHandle<SharedFunctionInfo> 1763 Compiler::GetSharedFunctionInfoForStreamedScript( 1764 Isolate* isolate, Handle<String> source, 1765 const ScriptDetails& script_details, ScriptOriginOptions origin_options, 1766 ScriptStreamingData* streaming_data) { 1767 ScriptCompileTimerScope compile_timer( 1768 isolate, ScriptCompiler::kNoCacheBecauseStreamingSource); 1769 PostponeInterruptsScope postpone(isolate); 1770 1771 int source_length = source->length(); 1772 isolate->counters()->total_load_size()->Increment(source_length); 1773 isolate->counters()->total_compile_size()->Increment(source_length); 1774 1775 ParseInfo* parse_info = streaming_data->info.get(); 1776 parse_info->UpdateBackgroundParseStatisticsOnMainThread(isolate); 1777 1778 // Check if compile cache already holds the SFI, if so no need to finalize 1779 // the code compiled on the background thread. 1780 CompilationCache* compilation_cache = isolate->compilation_cache(); 1781 MaybeHandle<SharedFunctionInfo> maybe_result = 1782 compilation_cache->LookupScript( 1783 source, script_details.name_obj, script_details.line_offset, 1784 script_details.column_offset, origin_options, 1785 isolate->native_context(), parse_info->language_mode()); 1786 if (!maybe_result.is_null()) { 1787 compile_timer.set_hit_isolate_cache(); 1788 } 1789 1790 if (maybe_result.is_null()) { 1791 // No cache entry found, finalize compilation of the script and add it to 1792 // the isolate cache. 1793 Handle<Script> script = 1794 NewScript(isolate, parse_info, source, script_details, origin_options, 1795 NOT_NATIVES_CODE); 1796 streaming_data->parser->UpdateStatistics(isolate, script); 1797 streaming_data->parser->HandleSourceURLComments(isolate, script); 1798 1799 if (parse_info->literal() == nullptr) { 1800 // Parsing has failed - report error messages. 1801 parse_info->pending_error_handler()->ReportErrors( 1802 isolate, script, parse_info->ast_value_factory()); 1803 } else { 1804 // Parsing has succeeded - finalize compilation. 1805 if (streaming_data->outer_function_job) { 1806 maybe_result = FinalizeTopLevel( 1807 parse_info, isolate, streaming_data->outer_function_job.get(), 1808 &streaming_data->inner_function_jobs); 1809 } else { 1810 // Compilation failed on background thread - throw an exception. 1811 FailWithPendingException(isolate, parse_info, 1812 Compiler::ClearExceptionFlag::KEEP_EXCEPTION); 1813 } 1814 } 1815 1816 // Add compiled code to the isolate cache. 1817 Handle<SharedFunctionInfo> result; 1818 if (maybe_result.ToHandle(&result)) { 1819 compilation_cache->PutScript(source, isolate->native_context(), 1820 parse_info->language_mode(), result); 1821 } 1822 } 1823 1824 streaming_data->Release(); 1825 return maybe_result; 1826 } 1827 1828 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( 1829 FunctionLiteral* literal, Handle<Script> script, Isolate* isolate) { 1830 // Precondition: code has been parsed and scopes have been analyzed. 1831 MaybeHandle<SharedFunctionInfo> maybe_existing; 1832 1833 // Find any previously allocated shared function info for the given literal. 1834 maybe_existing = script->FindSharedFunctionInfo(isolate, literal); 1835 1836 // If we found an existing shared function info, return it. 1837 Handle<SharedFunctionInfo> existing; 1838 if (maybe_existing.ToHandle(&existing)) { 1839 DCHECK(!existing->is_toplevel()); 1840 return existing; 1841 } 1842 1843 // Allocate a shared function info object which will be compiled lazily. 1844 Handle<SharedFunctionInfo> result = 1845 isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script, 1846 false); 1847 return result; 1848 } 1849 1850 MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function, 1851 BailoutId osr_offset, 1852 JavaScriptFrame* osr_frame) { 1853 DCHECK(!osr_offset.IsNone()); 1854 DCHECK_NOT_NULL(osr_frame); 1855 return GetOptimizedCode(function, ConcurrencyMode::kNotConcurrent, osr_offset, 1856 osr_frame); 1857 } 1858 1859 bool Compiler::FinalizeCompilationJob(OptimizedCompilationJob* raw_job, 1860 Isolate* isolate) { 1861 VMState<COMPILER> state(isolate); 1862 // Take ownership of compilation job. Deleting job also tears down the zone. 1863 std::unique_ptr<OptimizedCompilationJob> job(raw_job); 1864 return FinalizeOptimizedCompilationJob(job.get(), isolate) == 1865 CompilationJob::SUCCEEDED; 1866 } 1867 1868 bool Compiler::FinalizeCompilationJob(UnoptimizedCompilationJob* raw_job, 1869 Handle<SharedFunctionInfo> shared_info, 1870 Isolate* isolate) { 1871 VMState<BYTECODE_COMPILER> state(isolate); 1872 // Take ownership of compilation job. Deleting job also tears down the zone. 1873 std::unique_ptr<UnoptimizedCompilationJob> job(raw_job); 1874 return FinalizeUnoptimizedCompilationJob(job.get(), shared_info, isolate) == 1875 CompilationJob::SUCCEEDED; 1876 } 1877 1878 void Compiler::PostInstantiation(Handle<JSFunction> function, 1879 PretenureFlag pretenure) { 1880 Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate()); 1881 1882 if (FLAG_always_opt && shared->allows_lazy_compilation() && 1883 !shared->optimization_disabled() && !shared->HasAsmWasmData() && 1884 shared->is_compiled()) { 1885 JSFunction::EnsureFeedbackVector(function); 1886 1887 if (!function->IsOptimized()) { 1888 // Only mark for optimization if we don't already have optimized code. 1889 if (!function->HasOptimizedCode()) { 1890 function->MarkForOptimization(ConcurrencyMode::kNotConcurrent); 1891 } 1892 } 1893 } 1894 1895 if (shared->is_compiled() && !shared->HasAsmWasmData()) { 1896 JSFunction::EnsureFeedbackVector(function); 1897 1898 Code* code = function->feedback_vector()->optimized_code(); 1899 if (code != nullptr) { 1900 // Caching of optimized code enabled and optimized code found. 1901 DCHECK(!code->marked_for_deoptimization()); 1902 DCHECK(function->shared()->is_compiled()); 1903 function->set_code(code); 1904 } 1905 } 1906 1907 if (shared->is_toplevel() || shared->is_wrapped()) { 1908 // If it's a top-level script, report compilation to the debugger. 1909 Handle<Script> script( 1910 handle(Script::cast(shared->script()), function->GetIsolate())); 1911 function->GetIsolate()->debug()->OnAfterCompile(script); 1912 } 1913 } 1914 1915 // ---------------------------------------------------------------------------- 1916 // Implementation of ScriptStreamingData 1917 1918 ScriptStreamingData::ScriptStreamingData( 1919 ScriptCompiler::ExternalSourceStream* source_stream, 1920 ScriptCompiler::StreamedSource::Encoding encoding) 1921 : source_stream(source_stream), encoding(encoding) {} 1922 1923 ScriptStreamingData::~ScriptStreamingData() {} 1924 1925 void ScriptStreamingData::Release() { 1926 parser.reset(); 1927 info.reset(); 1928 outer_function_job.reset(); 1929 inner_function_jobs.clear(); 1930 } 1931 1932 } // namespace internal 1933 } // namespace v8 1934