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/asmjs/asm-js.h" 11 #include "src/asmjs/asm-typer.h" 12 #include "src/assembler-inl.h" 13 #include "src/ast/ast-numbering.h" 14 #include "src/ast/prettyprinter.h" 15 #include "src/ast/scopes.h" 16 #include "src/bootstrapper.h" 17 #include "src/codegen.h" 18 #include "src/compilation-cache.h" 19 #include "src/compiler-dispatcher/compiler-dispatcher.h" 20 #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" 21 #include "src/compiler/pipeline.h" 22 #include "src/crankshaft/hydrogen.h" 23 #include "src/debug/debug.h" 24 #include "src/debug/liveedit.h" 25 #include "src/frames-inl.h" 26 #include "src/full-codegen/full-codegen.h" 27 #include "src/globals.h" 28 #include "src/heap/heap.h" 29 #include "src/interpreter/interpreter.h" 30 #include "src/isolate-inl.h" 31 #include "src/log-inl.h" 32 #include "src/messages.h" 33 #include "src/parsing/parsing.h" 34 #include "src/parsing/rewriter.h" 35 #include "src/parsing/scanner-character-streams.h" 36 #include "src/runtime-profiler.h" 37 #include "src/snapshot/code-serializer.h" 38 #include "src/vm-state-inl.h" 39 40 namespace v8 { 41 namespace internal { 42 43 // A wrapper around a ParseInfo that detaches the parser handles from the 44 // underlying DeferredHandleScope and stores them in info_ on destruction. 45 class ParseHandleScope final { 46 public: 47 explicit ParseHandleScope(ParseInfo* info) 48 : deferred_(info->isolate()), info_(info) {} 49 ~ParseHandleScope() { info_->set_deferred_handles(deferred_.Detach()); } 50 51 private: 52 DeferredHandleScope deferred_; 53 ParseInfo* info_; 54 }; 55 56 // A wrapper around a CompilationInfo that detaches the Handles from 57 // the underlying DeferredHandleScope and stores them in info_ on 58 // destruction. 59 class CompilationHandleScope final { 60 public: 61 explicit CompilationHandleScope(CompilationInfo* info) 62 : deferred_(info->isolate()), info_(info) {} 63 ~CompilationHandleScope() { info_->set_deferred_handles(deferred_.Detach()); } 64 65 private: 66 DeferredHandleScope deferred_; 67 CompilationInfo* info_; 68 }; 69 70 // Helper that times a scoped region and records the elapsed time. 71 struct ScopedTimer { 72 explicit ScopedTimer(base::TimeDelta* location) : location_(location) { 73 DCHECK(location_ != NULL); 74 timer_.Start(); 75 } 76 77 ~ScopedTimer() { *location_ += timer_.Elapsed(); } 78 79 base::ElapsedTimer timer_; 80 base::TimeDelta* location_; 81 }; 82 83 // ---------------------------------------------------------------------------- 84 // Implementation of CompilationJob 85 86 CompilationJob::CompilationJob(Isolate* isolate, CompilationInfo* info, 87 const char* compiler_name, State initial_state) 88 : info_(info), 89 isolate_thread_id_(isolate->thread_id()), 90 compiler_name_(compiler_name), 91 state_(initial_state), 92 stack_limit_(isolate->stack_guard()->real_climit()), 93 executed_on_background_thread_(false) {} 94 95 CompilationJob::Status CompilationJob::PrepareJob() { 96 DCHECK(ThreadId::Current().Equals(info()->isolate()->thread_id())); 97 DisallowJavascriptExecution no_js(isolate()); 98 99 if (FLAG_trace_opt && info()->IsOptimizing()) { 100 OFStream os(stdout); 101 os << "[compiling method " << Brief(*info()->closure()) << " using " 102 << compiler_name_; 103 if (info()->is_osr()) os << " OSR"; 104 os << "]" << std::endl; 105 } 106 107 // Delegate to the underlying implementation. 108 DCHECK(state() == State::kReadyToPrepare); 109 ScopedTimer t(&time_taken_to_prepare_); 110 return UpdateState(PrepareJobImpl(), State::kReadyToExecute); 111 } 112 113 CompilationJob::Status CompilationJob::ExecuteJob() { 114 std::unique_ptr<DisallowHeapAllocation> no_allocation; 115 std::unique_ptr<DisallowHandleAllocation> no_handles; 116 std::unique_ptr<DisallowHandleDereference> no_deref; 117 std::unique_ptr<DisallowCodeDependencyChange> no_dependency_change; 118 if (can_execute_on_background_thread()) { 119 no_allocation.reset(new DisallowHeapAllocation()); 120 no_handles.reset(new DisallowHandleAllocation()); 121 no_deref.reset(new DisallowHandleDereference()); 122 no_dependency_change.reset(new DisallowCodeDependencyChange()); 123 executed_on_background_thread_ = 124 !ThreadId::Current().Equals(isolate_thread_id_); 125 } else { 126 DCHECK(ThreadId::Current().Equals(isolate_thread_id_)); 127 } 128 129 // Delegate to the underlying implementation. 130 DCHECK(state() == State::kReadyToExecute); 131 ScopedTimer t(&time_taken_to_execute_); 132 return UpdateState(ExecuteJobImpl(), State::kReadyToFinalize); 133 } 134 135 CompilationJob::Status CompilationJob::FinalizeJob() { 136 DCHECK(ThreadId::Current().Equals(info()->isolate()->thread_id())); 137 DisallowCodeDependencyChange no_dependency_change; 138 DisallowJavascriptExecution no_js(isolate()); 139 DCHECK(!info()->dependencies()->HasAborted()); 140 141 // Delegate to the underlying implementation. 142 DCHECK(state() == State::kReadyToFinalize); 143 ScopedTimer t(&time_taken_to_finalize_); 144 return UpdateState(FinalizeJobImpl(), State::kSucceeded); 145 } 146 147 CompilationJob::Status CompilationJob::RetryOptimization(BailoutReason reason) { 148 DCHECK(info_->IsOptimizing()); 149 info_->RetryOptimization(reason); 150 state_ = State::kFailed; 151 return FAILED; 152 } 153 154 CompilationJob::Status CompilationJob::AbortOptimization(BailoutReason reason) { 155 DCHECK(info_->IsOptimizing()); 156 info_->AbortOptimization(reason); 157 state_ = State::kFailed; 158 return FAILED; 159 } 160 161 void CompilationJob::RecordUnoptimizedCompilationStats() const { 162 int code_size; 163 if (info()->has_bytecode_array()) { 164 code_size = info()->bytecode_array()->SizeIncludingMetadata(); 165 } else { 166 code_size = info()->code()->SizeIncludingMetadata(); 167 } 168 169 Counters* counters = isolate()->counters(); 170 // TODO(4280): Rename counters from "baseline" to "unoptimized" eventually. 171 counters->total_baseline_code_size()->Increment(code_size); 172 counters->total_baseline_compile_count()->Increment(1); 173 174 // TODO(5203): Add timers for each phase of compilation. 175 } 176 177 void CompilationJob::RecordOptimizedCompilationStats() const { 178 DCHECK(info()->IsOptimizing()); 179 Handle<JSFunction> function = info()->closure(); 180 if (!function->IsOptimized()) { 181 // Concurrent recompilation and OSR may race. Increment only once. 182 int opt_count = function->shared()->opt_count(); 183 function->shared()->set_opt_count(opt_count + 1); 184 } 185 double ms_creategraph = time_taken_to_prepare_.InMillisecondsF(); 186 double ms_optimize = time_taken_to_execute_.InMillisecondsF(); 187 double ms_codegen = time_taken_to_finalize_.InMillisecondsF(); 188 if (FLAG_trace_opt) { 189 PrintF("[optimizing "); 190 function->ShortPrint(); 191 PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize, 192 ms_codegen); 193 } 194 if (FLAG_trace_opt_stats) { 195 static double compilation_time = 0.0; 196 static int compiled_functions = 0; 197 static int code_size = 0; 198 199 compilation_time += (ms_creategraph + ms_optimize + ms_codegen); 200 compiled_functions++; 201 code_size += function->shared()->SourceSize(); 202 PrintF("Compiled: %d functions with %d byte source size in %fms.\n", 203 compiled_functions, code_size, compilation_time); 204 } 205 if (FLAG_hydrogen_stats) { 206 isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_prepare_, 207 time_taken_to_execute_, 208 time_taken_to_finalize_); 209 } 210 } 211 212 Isolate* CompilationJob::isolate() const { return info()->isolate(); } 213 214 namespace { 215 216 void AddWeakObjectToCodeDependency(Isolate* isolate, Handle<HeapObject> object, 217 Handle<Code> code) { 218 Handle<WeakCell> cell = Code::WeakCellFor(code); 219 Heap* heap = isolate->heap(); 220 if (heap->InNewSpace(*object)) { 221 heap->AddWeakNewSpaceObjectToCodeDependency(object, cell); 222 } else { 223 Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(object)); 224 dep = 225 DependentCode::InsertWeakCode(dep, DependentCode::kWeakCodeGroup, cell); 226 heap->AddWeakObjectToCodeDependency(object, dep); 227 } 228 } 229 230 } // namespace 231 232 void CompilationJob::RegisterWeakObjectsInOptimizedCode(Handle<Code> code) { 233 // TODO(turbofan): Move this to pipeline.cc once Crankshaft dies. 234 Isolate* const isolate = code->GetIsolate(); 235 DCHECK(code->is_optimized_code()); 236 std::vector<Handle<Map>> maps; 237 std::vector<Handle<HeapObject>> objects; 238 { 239 DisallowHeapAllocation no_gc; 240 int const mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 241 RelocInfo::ModeMask(RelocInfo::CELL); 242 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { 243 RelocInfo::Mode mode = it.rinfo()->rmode(); 244 if (mode == RelocInfo::CELL && 245 code->IsWeakObjectInOptimizedCode(it.rinfo()->target_cell())) { 246 objects.push_back(handle(it.rinfo()->target_cell(), isolate)); 247 } else if (mode == RelocInfo::EMBEDDED_OBJECT && 248 code->IsWeakObjectInOptimizedCode( 249 it.rinfo()->target_object())) { 250 Handle<HeapObject> object(HeapObject::cast(it.rinfo()->target_object()), 251 isolate); 252 if (object->IsMap()) { 253 maps.push_back(Handle<Map>::cast(object)); 254 } else { 255 objects.push_back(object); 256 } 257 } 258 } 259 } 260 for (Handle<Map> map : maps) { 261 if (map->dependent_code()->IsEmpty(DependentCode::kWeakCodeGroup)) { 262 isolate->heap()->AddRetainedMap(map); 263 } 264 Map::AddDependentCode(map, DependentCode::kWeakCodeGroup, code); 265 } 266 for (Handle<HeapObject> object : objects) { 267 AddWeakObjectToCodeDependency(isolate, object, code); 268 } 269 code->set_can_have_weak_objects(true); 270 } 271 272 // ---------------------------------------------------------------------------- 273 // Local helper methods that make up the compilation pipeline. 274 275 namespace { 276 277 void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag, 278 CompilationInfo* info) { 279 // Log the code generation. If source information is available include 280 // script name and line number. Check explicitly whether logging is 281 // enabled as finding the line number is not free. 282 if (info->isolate()->logger()->is_logging_code_events() || 283 info->isolate()->is_profiling()) { 284 Handle<SharedFunctionInfo> shared = info->shared_info(); 285 Handle<Script> script = info->parse_info()->script(); 286 Handle<AbstractCode> abstract_code = 287 info->has_bytecode_array() 288 ? Handle<AbstractCode>::cast(info->bytecode_array()) 289 : Handle<AbstractCode>::cast(info->code()); 290 if (abstract_code.is_identical_to( 291 info->isolate()->builtins()->CompileLazy())) { 292 return; 293 } 294 int line_num = Script::GetLineNumber(script, shared->start_position()) + 1; 295 int column_num = 296 Script::GetColumnNumber(script, shared->start_position()) + 1; 297 String* script_name = script->name()->IsString() 298 ? String::cast(script->name()) 299 : info->isolate()->heap()->empty_string(); 300 CodeEventListener::LogEventsAndTags log_tag = 301 Logger::ToNativeByScript(tag, *script); 302 PROFILE(info->isolate(), 303 CodeCreateEvent(log_tag, *abstract_code, *shared, script_name, 304 line_num, column_num)); 305 } 306 } 307 308 void EnsureFeedbackMetadata(CompilationInfo* info) { 309 DCHECK(info->has_shared_info()); 310 311 // If no type feedback metadata exists, create it. At this point the 312 // AstNumbering pass has already run. Note the snapshot can contain outdated 313 // vectors for a different configuration, hence we also recreate a new vector 314 // when the function is not compiled (i.e. no code was serialized). 315 316 // TODO(mvstanton): reintroduce is_empty() predicate to feedback_metadata(). 317 if (info->shared_info()->feedback_metadata()->length() == 0 || 318 !info->shared_info()->is_compiled()) { 319 Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New( 320 info->isolate(), info->literal()->feedback_vector_spec()); 321 info->shared_info()->set_feedback_metadata(*feedback_metadata); 322 } 323 324 // It's very important that recompiles do not alter the structure of the type 325 // feedback vector. Verify that the structure fits the function literal. 326 CHECK(!info->shared_info()->feedback_metadata()->SpecDiffersFrom( 327 info->literal()->feedback_vector_spec())); 328 } 329 330 bool UseTurboFan(Handle<SharedFunctionInfo> shared) { 331 if (shared->optimization_disabled()) { 332 return false; 333 } 334 335 bool must_use_ignition_turbo = shared->must_use_ignition_turbo(); 336 337 // Check the enabling conditions for Turbofan. 338 // 1. "use asm" code. 339 bool is_turbofanable_asm = FLAG_turbo_asm && shared->asm_function(); 340 341 // 2. Fallback for features unsupported by Crankshaft. 342 bool is_unsupported_by_crankshaft_but_turbofanable = 343 must_use_ignition_turbo && strcmp(FLAG_turbo_filter, "~~") == 0; 344 345 // 3. Explicitly enabled by the command-line filter. 346 bool passes_turbo_filter = shared->PassesFilter(FLAG_turbo_filter); 347 348 return is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable || 349 passes_turbo_filter; 350 } 351 352 bool ShouldUseIgnition(Handle<SharedFunctionInfo> shared, 353 bool marked_as_debug) { 354 // Code which can't be supported by the old pipeline should use Ignition. 355 if (shared->must_use_ignition_turbo()) return true; 356 357 // Resumable functions are not supported by {FullCodeGenerator}, suspended 358 // activations stored as {JSGeneratorObject} on the heap always assume the 359 // underlying code to be based on the bytecode array. 360 DCHECK(!IsResumableFunction(shared->kind())); 361 362 // Skip Ignition for asm.js functions. 363 if (shared->asm_function()) return false; 364 365 // Skip Ignition for asm wasm code. 366 if (FLAG_validate_asm && shared->HasAsmWasmData()) { 367 return false; 368 } 369 370 // When requesting debug code as a replacement for existing code, we provide 371 // the same kind as the existing code (to prevent implicit tier-change). 372 if (marked_as_debug && shared->is_compiled()) { 373 return !shared->HasBaselineCode(); 374 } 375 376 // Code destined for TurboFan should be compiled with Ignition first. 377 if (UseTurboFan(shared)) return true; 378 379 // Only use Ignition for any other function if FLAG_ignition is true. 380 return FLAG_ignition; 381 } 382 383 bool ShouldUseIgnition(CompilationInfo* info) { 384 DCHECK(info->has_shared_info()); 385 return ShouldUseIgnition(info->shared_info(), info->is_debug()); 386 } 387 388 bool UseAsmWasm(DeclarationScope* scope, Handle<SharedFunctionInfo> shared_info, 389 bool is_debug) { 390 return FLAG_validate_asm && scope->asm_module() && 391 !shared_info->is_asm_wasm_broken() && !is_debug; 392 } 393 394 bool UseCompilerDispatcher(Compiler::ConcurrencyMode inner_function_mode, 395 CompilerDispatcher* dispatcher, 396 DeclarationScope* scope, 397 Handle<SharedFunctionInfo> shared_info, 398 bool is_debug, bool will_serialize) { 399 return FLAG_compiler_dispatcher_eager_inner && 400 inner_function_mode == Compiler::CONCURRENT && 401 dispatcher->IsEnabled() && !is_debug && !will_serialize && 402 !UseAsmWasm(scope, shared_info, is_debug); 403 } 404 405 CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) { 406 // Function should have been parsed and analyzed before creating a compilation 407 // job. 408 DCHECK_NOT_NULL(info->literal()); 409 DCHECK_NOT_NULL(info->scope()); 410 411 if (ShouldUseIgnition(info)) { 412 return interpreter::Interpreter::NewCompilationJob(info); 413 } else { 414 return FullCodeGenerator::NewCompilationJob(info); 415 } 416 } 417 418 void InstallSharedScopeInfo(CompilationInfo* info, 419 Handle<SharedFunctionInfo> shared) { 420 Handle<ScopeInfo> scope_info = info->scope()->scope_info(); 421 shared->set_scope_info(*scope_info); 422 Scope* outer_scope = info->scope()->GetOuterScopeWithContext(); 423 if (outer_scope) { 424 shared->set_outer_scope_info(*outer_scope->scope_info()); 425 } 426 } 427 428 void InstallSharedCompilationResult(CompilationInfo* info, 429 Handle<SharedFunctionInfo> shared) { 430 // TODO(mstarzinger): Compiling for debug code might be used to reveal inner 431 // functions via {FindSharedFunctionInfoInScript}, in which case we end up 432 // regenerating existing bytecode. Fix this! 433 if (info->is_debug() && info->has_bytecode_array()) { 434 shared->ClearBytecodeArray(); 435 } 436 DCHECK(!info->code().is_null()); 437 shared->ReplaceCode(*info->code()); 438 if (info->has_bytecode_array()) { 439 DCHECK(!shared->HasBytecodeArray()); // Only compiled once. 440 shared->set_bytecode_array(*info->bytecode_array()); 441 } 442 } 443 444 void InstallUnoptimizedCode(CompilationInfo* info) { 445 Handle<SharedFunctionInfo> shared = info->shared_info(); 446 447 // Update the shared function info with the scope info. 448 InstallSharedScopeInfo(info, shared); 449 450 // Install compilation result on the shared function info 451 InstallSharedCompilationResult(info, shared); 452 } 453 454 CompilationJob::Status FinalizeUnoptimizedCompilationJob(CompilationJob* job) { 455 CompilationJob::Status status = job->FinalizeJob(); 456 if (status == CompilationJob::SUCCEEDED) { 457 CompilationInfo* info = job->info(); 458 EnsureFeedbackMetadata(info); 459 DCHECK(!info->code().is_null()); 460 if (info->parse_info()->literal()->should_be_used_once_hint()) { 461 info->code()->MarkToBeExecutedOnce(info->isolate()); 462 } 463 InstallUnoptimizedCode(info); 464 RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, info); 465 job->RecordUnoptimizedCompilationStats(); 466 } 467 return status; 468 } 469 470 void SetSharedFunctionFlagsFromLiteral(FunctionLiteral* literal, 471 Handle<SharedFunctionInfo> shared_info) { 472 shared_info->set_ast_node_count(literal->ast_node_count()); 473 if (literal->dont_optimize_reason() != kNoReason) { 474 shared_info->DisableOptimization(literal->dont_optimize_reason()); 475 } 476 if (literal->flags() & AstProperties::kMustUseIgnitionTurbo) { 477 shared_info->set_must_use_ignition_turbo(true); 478 } 479 } 480 481 bool Renumber(ParseInfo* parse_info, 482 Compiler::EagerInnerFunctionLiterals* eager_literals) { 483 RuntimeCallTimerScope runtimeTimer(parse_info->isolate(), 484 &RuntimeCallStats::CompileRenumber); 485 if (!AstNumbering::Renumber( 486 parse_info->isolate()->stack_guard()->real_climit(), 487 parse_info->zone(), parse_info->literal(), eager_literals)) { 488 return false; 489 } 490 if (!parse_info->shared_info().is_null()) { 491 SetSharedFunctionFlagsFromLiteral(parse_info->literal(), 492 parse_info->shared_info()); 493 } 494 return true; 495 } 496 497 bool GenerateUnoptimizedCode(CompilationInfo* info) { 498 if (UseAsmWasm(info->scope(), info->shared_info(), info->is_debug())) { 499 EnsureFeedbackMetadata(info); 500 MaybeHandle<FixedArray> wasm_data; 501 wasm_data = AsmJs::CompileAsmViaWasm(info); 502 if (!wasm_data.is_null()) { 503 info->shared_info()->set_asm_wasm_data(*wasm_data.ToHandleChecked()); 504 info->SetCode(info->isolate()->builtins()->InstantiateAsmJs()); 505 InstallUnoptimizedCode(info); 506 return true; 507 } 508 } 509 510 std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info)); 511 if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false; 512 if (job->ExecuteJob() != CompilationJob::SUCCEEDED) return false; 513 if (FinalizeUnoptimizedCompilationJob(job.get()) != 514 CompilationJob::SUCCEEDED) { 515 return false; 516 } 517 return true; 518 } 519 520 bool CompileUnoptimizedInnerFunctions( 521 Compiler::EagerInnerFunctionLiterals* literals, 522 Compiler::ConcurrencyMode inner_function_mode, 523 std::shared_ptr<Zone> parse_zone, CompilationInfo* outer_info) { 524 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 525 "V8.CompileUnoptimizedInnerFunctions"); 526 Isolate* isolate = outer_info->isolate(); 527 Handle<Script> script = outer_info->script(); 528 bool is_debug = outer_info->is_debug(); 529 bool will_serialize = outer_info->will_serialize(); 530 RuntimeCallTimerScope runtimeTimer(isolate, 531 &RuntimeCallStats::CompileInnerFunction); 532 533 for (auto it : *literals) { 534 FunctionLiteral* literal = it->value(); 535 Handle<SharedFunctionInfo> shared = 536 Compiler::GetSharedFunctionInfo(literal, script, outer_info); 537 if (shared->is_compiled()) continue; 538 539 // The {literal} has already been numbered because AstNumbering decends into 540 // eagerly compiled function literals. 541 SetSharedFunctionFlagsFromLiteral(literal, shared); 542 543 // Try to enqueue the eager function on the compiler dispatcher. 544 CompilerDispatcher* dispatcher = isolate->compiler_dispatcher(); 545 if (UseCompilerDispatcher(inner_function_mode, dispatcher, literal->scope(), 546 shared, is_debug, will_serialize) && 547 dispatcher->EnqueueAndStep(outer_info->script(), shared, literal, 548 parse_zone, 549 outer_info->parse_info()->deferred_handles(), 550 outer_info->deferred_handles())) { 551 // If we have successfully queued up the function for compilation on the 552 // compiler dispatcher then we are done. 553 continue; 554 } else { 555 // Otherwise generate unoptimized code now. 556 ParseInfo parse_info(script); 557 CompilationInfo info(parse_info.zone(), &parse_info, 558 Handle<JSFunction>::null()); 559 560 parse_info.set_literal(literal); 561 parse_info.set_shared_info(shared); 562 parse_info.set_function_literal_id(shared->function_literal_id()); 563 parse_info.set_language_mode(literal->scope()->language_mode()); 564 parse_info.set_ast_value_factory( 565 outer_info->parse_info()->ast_value_factory()); 566 parse_info.set_ast_value_factory_owned(false); 567 568 if (will_serialize) info.PrepareForSerializing(); 569 if (is_debug) info.MarkAsDebug(); 570 571 if (!GenerateUnoptimizedCode(&info)) { 572 if (!isolate->has_pending_exception()) isolate->StackOverflow(); 573 return false; 574 } 575 } 576 } 577 return true; 578 } 579 580 bool InnerFunctionIsAsmModule( 581 ThreadedList<ThreadedListZoneEntry<FunctionLiteral*>>* literals) { 582 for (auto it : *literals) { 583 FunctionLiteral* literal = it->value(); 584 if (literal->scope()->IsAsmModule()) return true; 585 } 586 return false; 587 } 588 589 bool CompileUnoptimizedCode(CompilationInfo* info, 590 Compiler::ConcurrencyMode inner_function_mode) { 591 Isolate* isolate = info->isolate(); 592 DCHECK(AllowCompilation::IsAllowed(isolate)); 593 594 Compiler::EagerInnerFunctionLiterals inner_literals; 595 { 596 std::unique_ptr<CompilationHandleScope> compilation_handle_scope; 597 if (inner_function_mode == Compiler::CONCURRENT) { 598 compilation_handle_scope.reset(new CompilationHandleScope(info)); 599 } 600 if (!Compiler::Analyze(info->parse_info(), &inner_literals)) { 601 if (!isolate->has_pending_exception()) isolate->StackOverflow(); 602 return false; 603 } 604 } 605 606 // Disable concurrent inner compilation for asm-wasm code. 607 // TODO(rmcilroy,bradnelson): Remove this AsmWasm check once the asm-wasm 608 // builder doesn't do parsing when visiting function declarations. 609 if (info->scope()->IsAsmModule() || 610 InnerFunctionIsAsmModule(&inner_literals)) { 611 inner_function_mode = Compiler::NOT_CONCURRENT; 612 } 613 614 std::shared_ptr<Zone> parse_zone; 615 if (inner_function_mode == Compiler::CONCURRENT) { 616 // Seal the parse zone so that it can be shared by parallel inner function 617 // compilation jobs. 618 DCHECK_NE(info->parse_info()->zone(), info->zone()); 619 parse_zone = info->parse_info()->zone_shared(); 620 parse_zone->Seal(); 621 } 622 623 if (!CompileUnoptimizedInnerFunctions(&inner_literals, inner_function_mode, 624 parse_zone, info) || 625 !GenerateUnoptimizedCode(info)) { 626 if (!isolate->has_pending_exception()) isolate->StackOverflow(); 627 return false; 628 } 629 630 return true; 631 } 632 633 void EnsureSharedFunctionInfosArrayOnScript(ParseInfo* info) { 634 DCHECK(info->is_toplevel()); 635 DCHECK(!info->script().is_null()); 636 if (info->script()->shared_function_infos()->length() > 0) { 637 DCHECK_EQ(info->script()->shared_function_infos()->length(), 638 info->max_function_literal_id() + 1); 639 return; 640 } 641 Isolate* isolate = info->isolate(); 642 Handle<FixedArray> infos( 643 isolate->factory()->NewFixedArray(info->max_function_literal_id() + 1)); 644 info->script()->set_shared_function_infos(*infos); 645 } 646 647 MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode( 648 CompilationInfo* info, Compiler::ConcurrencyMode inner_function_mode) { 649 RuntimeCallTimerScope runtimeTimer( 650 info->isolate(), &RuntimeCallStats::CompileGetUnoptimizedCode); 651 VMState<COMPILER> state(info->isolate()); 652 PostponeInterruptsScope postpone(info->isolate()); 653 654 // Parse and update ParseInfo with the results. 655 { 656 if (!parsing::ParseAny(info->parse_info(), 657 inner_function_mode != Compiler::CONCURRENT)) { 658 return MaybeHandle<Code>(); 659 } 660 661 if (inner_function_mode == Compiler::CONCURRENT) { 662 ParseHandleScope parse_handles(info->parse_info()); 663 info->parse_info()->ReopenHandlesInNewHandleScope(); 664 info->parse_info()->ast_value_factory()->Internalize(info->isolate()); 665 } 666 } 667 668 if (info->parse_info()->is_toplevel()) { 669 EnsureSharedFunctionInfosArrayOnScript(info->parse_info()); 670 } 671 DCHECK_EQ(info->shared_info()->language_mode(), 672 info->literal()->language_mode()); 673 674 // Compile either unoptimized code or bytecode for the interpreter. 675 if (!CompileUnoptimizedCode(info, inner_function_mode)) { 676 return MaybeHandle<Code>(); 677 } 678 679 // Record the function compilation event. 680 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, info); 681 682 return info->code(); 683 } 684 685 MUST_USE_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeMap( 686 Handle<JSFunction> function, BailoutId osr_ast_id) { 687 RuntimeCallTimerScope runtimeTimer( 688 function->GetIsolate(), 689 &RuntimeCallStats::CompileGetFromOptimizedCodeMap); 690 Handle<SharedFunctionInfo> shared(function->shared()); 691 DisallowHeapAllocation no_gc; 692 Code* code = shared->SearchOptimizedCodeMap( 693 function->context()->native_context(), osr_ast_id); 694 if (code != nullptr) { 695 // Caching of optimized code enabled and optimized code found. 696 DCHECK(!code->marked_for_deoptimization()); 697 DCHECK(function->shared()->is_compiled()); 698 return Handle<Code>(code); 699 } 700 return MaybeHandle<Code>(); 701 } 702 703 void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { 704 Handle<Code> code = info->code(); 705 if (code->kind() != Code::OPTIMIZED_FUNCTION) return; // Nothing to do. 706 707 // Function context specialization folds-in the function context, 708 // so no sharing can occur. 709 if (info->is_function_context_specializing()) return; 710 // Frame specialization implies function context specialization. 711 DCHECK(!info->is_frame_specializing()); 712 713 // TODO(4764): When compiling for OSR from bytecode, BailoutId might derive 714 // from bytecode offset and overlap with actual BailoutId. No caching! 715 if (info->is_osr() && info->is_optimizing_from_bytecode()) return; 716 717 // Cache optimized context-specific code. 718 Handle<JSFunction> function = info->closure(); 719 Handle<SharedFunctionInfo> shared(function->shared()); 720 Handle<Context> native_context(function->context()->native_context()); 721 SharedFunctionInfo::AddToOptimizedCodeMap(shared, native_context, code, 722 info->osr_ast_id()); 723 } 724 725 bool GetOptimizedCodeNow(CompilationJob* job) { 726 CompilationInfo* info = job->info(); 727 Isolate* isolate = info->isolate(); 728 729 // Parsing is not required when optimizing from existing bytecode. 730 if (!info->is_optimizing_from_bytecode()) { 731 if (!Compiler::ParseAndAnalyze(info->parse_info())) return false; 732 EnsureFeedbackMetadata(info); 733 } 734 735 JSFunction::EnsureLiterals(info->closure()); 736 737 TimerEventScope<TimerEventRecompileSynchronous> timer(isolate); 738 RuntimeCallTimerScope runtimeTimer(isolate, 739 &RuntimeCallStats::RecompileSynchronous); 740 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 741 "V8.RecompileSynchronous"); 742 743 if (job->PrepareJob() != CompilationJob::SUCCEEDED || 744 job->ExecuteJob() != CompilationJob::SUCCEEDED || 745 job->FinalizeJob() != CompilationJob::SUCCEEDED) { 746 if (FLAG_trace_opt) { 747 PrintF("[aborted optimizing "); 748 info->closure()->ShortPrint(); 749 PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason())); 750 } 751 return false; 752 } 753 754 // Success! 755 job->RecordOptimizedCompilationStats(); 756 DCHECK(!isolate->has_pending_exception()); 757 InsertCodeIntoOptimizedCodeMap(info); 758 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, info); 759 return true; 760 } 761 762 bool GetOptimizedCodeLater(CompilationJob* job) { 763 CompilationInfo* info = job->info(); 764 Isolate* isolate = info->isolate(); 765 766 if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) { 767 if (FLAG_trace_concurrent_recompilation) { 768 PrintF(" ** Compilation queue full, will retry optimizing "); 769 info->closure()->ShortPrint(); 770 PrintF(" later.\n"); 771 } 772 return false; 773 } 774 775 if (isolate->heap()->HighMemoryPressure()) { 776 if (FLAG_trace_concurrent_recompilation) { 777 PrintF(" ** High memory pressure, will retry optimizing "); 778 info->closure()->ShortPrint(); 779 PrintF(" later.\n"); 780 } 781 return false; 782 } 783 784 // Parsing is not required when optimizing from existing bytecode. 785 if (!info->is_optimizing_from_bytecode()) { 786 if (!Compiler::ParseAndAnalyze(info->parse_info())) return false; 787 EnsureFeedbackMetadata(info); 788 } 789 790 JSFunction::EnsureLiterals(info->closure()); 791 792 TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate()); 793 RuntimeCallTimerScope runtimeTimer(info->isolate(), 794 &RuntimeCallStats::RecompileSynchronous); 795 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 796 "V8.RecompileSynchronous"); 797 798 if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false; 799 isolate->optimizing_compile_dispatcher()->QueueForOptimization(job); 800 801 if (FLAG_trace_concurrent_recompilation) { 802 PrintF(" ** Queued "); 803 info->closure()->ShortPrint(); 804 PrintF(" for concurrent optimization.\n"); 805 } 806 return true; 807 } 808 809 MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, 810 Compiler::ConcurrencyMode mode, 811 BailoutId osr_ast_id = BailoutId::None(), 812 JavaScriptFrame* osr_frame = nullptr) { 813 Isolate* isolate = function->GetIsolate(); 814 Handle<SharedFunctionInfo> shared(function->shared(), isolate); 815 816 bool ignition_osr = osr_frame && osr_frame->is_interpreted(); 817 DCHECK_IMPLIES(ignition_osr, !osr_ast_id.IsNone()); 818 DCHECK_IMPLIES(ignition_osr, FLAG_ignition_osr); 819 820 // Shared function no longer needs to be tiered up 821 shared->set_marked_for_tier_up(false); 822 823 Handle<Code> cached_code; 824 // TODO(4764): When compiling for OSR from bytecode, BailoutId might derive 825 // from bytecode offset and overlap with actual BailoutId. No lookup! 826 if (!ignition_osr && 827 GetCodeFromOptimizedCodeMap(function, osr_ast_id) 828 .ToHandle(&cached_code)) { 829 if (FLAG_trace_opt) { 830 PrintF("[found optimized code for "); 831 function->ShortPrint(); 832 if (!osr_ast_id.IsNone()) { 833 PrintF(" at OSR AST id %d", osr_ast_id.ToInt()); 834 } 835 PrintF("]\n"); 836 } 837 return cached_code; 838 } 839 840 // Reset profiler ticks, function is no longer considered hot. 841 DCHECK(shared->is_compiled()); 842 if (shared->HasBaselineCode()) { 843 shared->code()->set_profiler_ticks(0); 844 } else if (shared->HasBytecodeArray()) { 845 shared->set_profiler_ticks(0); 846 } 847 848 VMState<COMPILER> state(isolate); 849 DCHECK(!isolate->has_pending_exception()); 850 PostponeInterruptsScope postpone(isolate); 851 bool use_turbofan = UseTurboFan(shared) || ignition_osr; 852 bool has_script = shared->script()->IsScript(); 853 // BUG(5946): This DCHECK is necessary to make certain that we won't tolerate 854 // the lack of a script without bytecode. 855 DCHECK_IMPLIES(!has_script, ShouldUseIgnition(shared, false)); 856 std::unique_ptr<CompilationJob> job( 857 use_turbofan ? compiler::Pipeline::NewCompilationJob(function, has_script) 858 : new HCompilationJob(function)); 859 CompilationInfo* info = job->info(); 860 ParseInfo* parse_info = info->parse_info(); 861 862 info->SetOptimizingForOsr(osr_ast_id, osr_frame); 863 864 // Do not use Crankshaft/TurboFan if we need to be able to set break points. 865 if (info->shared_info()->HasDebugInfo()) { 866 info->AbortOptimization(kFunctionBeingDebugged); 867 return MaybeHandle<Code>(); 868 } 869 870 // Limit the number of times we try to optimize functions. 871 const int kMaxOptCount = 872 FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000; 873 if (info->shared_info()->opt_count() > kMaxOptCount) { 874 info->AbortOptimization(kDeoptimizedTooManyTimes); 875 return MaybeHandle<Code>(); 876 } 877 878 TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate); 879 RuntimeCallTimerScope runtimeTimer(isolate, &RuntimeCallStats::OptimizeCode); 880 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.OptimizeCode"); 881 882 // TurboFan can optimize directly from existing bytecode. 883 if (use_turbofan && ShouldUseIgnition(info)) { 884 if (info->is_osr() && !ignition_osr) return MaybeHandle<Code>(); 885 DCHECK(shared->HasBytecodeArray()); 886 info->MarkAsOptimizeFromBytecode(); 887 } 888 889 // Verify that OSR compilations are delegated to the correct graph builder. 890 // Depending on the underlying frame the semantics of the {BailoutId} differ 891 // and the various graph builders hard-code a certain semantic: 892 // - Interpreter : The BailoutId represents a bytecode offset. 893 // - FullCodegen : The BailoutId represents the id of an AST node. 894 DCHECK_IMPLIES(info->is_osr() && ignition_osr, 895 info->is_optimizing_from_bytecode()); 896 DCHECK_IMPLIES(info->is_osr() && !ignition_osr, 897 !info->is_optimizing_from_bytecode()); 898 899 // In case of concurrent recompilation, all handles below this point will be 900 // allocated in a deferred handle scope that is detached and handed off to 901 // the background thread when we return. 902 std::unique_ptr<CompilationHandleScope> compilation; 903 if (mode == Compiler::CONCURRENT) { 904 compilation.reset(new CompilationHandleScope(info)); 905 } 906 907 // In case of TurboFan, all handles below will be canonicalized. 908 std::unique_ptr<CanonicalHandleScope> canonical; 909 if (use_turbofan) canonical.reset(new CanonicalHandleScope(info->isolate())); 910 911 // Reopen handles in the new CompilationHandleScope. 912 info->ReopenHandlesInNewHandleScope(); 913 parse_info->ReopenHandlesInNewHandleScope(); 914 915 if (mode == Compiler::CONCURRENT) { 916 if (GetOptimizedCodeLater(job.get())) { 917 job.release(); // The background recompile job owns this now. 918 return isolate->builtins()->InOptimizationQueue(); 919 } 920 } else { 921 if (GetOptimizedCodeNow(job.get())) return info->code(); 922 } 923 924 if (isolate->has_pending_exception()) isolate->clear_pending_exception(); 925 return MaybeHandle<Code>(); 926 } 927 928 CompilationJob::Status FinalizeOptimizedCompilationJob(CompilationJob* job) { 929 CompilationInfo* info = job->info(); 930 Isolate* isolate = info->isolate(); 931 932 TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate()); 933 RuntimeCallTimerScope runtimeTimer(isolate, 934 &RuntimeCallStats::RecompileSynchronous); 935 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 936 "V8.RecompileSynchronous"); 937 938 Handle<SharedFunctionInfo> shared = info->shared_info(); 939 940 // Reset profiler ticks, function is no longer considered hot. 941 if (shared->HasBaselineCode()) { 942 shared->code()->set_profiler_ticks(0); 943 } else if (shared->HasBytecodeArray()) { 944 shared->set_profiler_ticks(0); 945 } 946 947 DCHECK(!shared->HasDebugInfo()); 948 949 // 1) Optimization on the concurrent thread may have failed. 950 // 2) The function may have already been optimized by OSR. Simply continue. 951 // Except when OSR already disabled optimization for some reason. 952 // 3) The code may have already been invalidated due to dependency change. 953 // 4) Code generation may have failed. 954 if (job->state() == CompilationJob::State::kReadyToFinalize) { 955 if (shared->optimization_disabled()) { 956 job->RetryOptimization(kOptimizationDisabled); 957 } else if (info->dependencies()->HasAborted()) { 958 job->RetryOptimization(kBailedOutDueToDependencyChange); 959 } else if (job->FinalizeJob() == CompilationJob::SUCCEEDED) { 960 job->RecordOptimizedCompilationStats(); 961 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, info); 962 if (shared->SearchOptimizedCodeMap(info->context()->native_context(), 963 info->osr_ast_id()) == nullptr) { 964 InsertCodeIntoOptimizedCodeMap(info); 965 } 966 if (FLAG_trace_opt) { 967 PrintF("[completed optimizing "); 968 info->closure()->ShortPrint(); 969 PrintF("]\n"); 970 } 971 info->closure()->ReplaceCode(*info->code()); 972 return CompilationJob::SUCCEEDED; 973 } 974 } 975 976 DCHECK(job->state() == CompilationJob::State::kFailed); 977 if (FLAG_trace_opt) { 978 PrintF("[aborted optimizing "); 979 info->closure()->ShortPrint(); 980 PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason())); 981 } 982 info->closure()->ReplaceCode(shared->code()); 983 return CompilationJob::FAILED; 984 } 985 986 MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) { 987 Isolate* isolate = function->GetIsolate(); 988 VMState<COMPILER> state(isolate); 989 PostponeInterruptsScope postpone(isolate); 990 ParseInfo parse_info(handle(function->shared())); 991 CompilationInfo info(parse_info.zone(), &parse_info, function); 992 993 DCHECK(function->shared()->is_compiled()); 994 995 // Function no longer needs to be tiered up 996 function->shared()->set_marked_for_tier_up(false); 997 998 // Reset profiler ticks, function is no longer considered hot. 999 if (function->shared()->HasBytecodeArray()) { 1000 function->shared()->set_profiler_ticks(0); 1001 } 1002 1003 // Nothing left to do if the function already has baseline code. 1004 if (function->shared()->code()->kind() == Code::FUNCTION) { 1005 return Handle<Code>(function->shared()->code()); 1006 } 1007 1008 // We do not switch to baseline code when the debugger might have created a 1009 // copy of the bytecode with break slots to be able to set break points. 1010 if (function->shared()->HasDebugInfo()) { 1011 return MaybeHandle<Code>(); 1012 } 1013 1014 // Don't generate full-codegen code for functions it can't support. 1015 if (function->shared()->must_use_ignition_turbo()) { 1016 return MaybeHandle<Code>(); 1017 } 1018 DCHECK(!IsResumableFunction(function->shared()->kind())); 1019 1020 if (FLAG_trace_opt) { 1021 OFStream os(stdout); 1022 os << "[switching method " << Brief(*function) << " to baseline code]" 1023 << std::endl; 1024 } 1025 1026 // Parse and update CompilationInfo with the results. 1027 if (!parsing::ParseFunction(info.parse_info())) return MaybeHandle<Code>(); 1028 Handle<SharedFunctionInfo> shared = info.shared_info(); 1029 DCHECK_EQ(shared->language_mode(), info.literal()->language_mode()); 1030 1031 // Compile baseline code using the full code generator. 1032 if (!Compiler::Analyze(info.parse_info()) || 1033 !FullCodeGenerator::MakeCode(&info)) { 1034 if (!isolate->has_pending_exception()) isolate->StackOverflow(); 1035 return MaybeHandle<Code>(); 1036 } 1037 1038 // Update the shared function info with the scope info. 1039 InstallSharedScopeInfo(&info, shared); 1040 1041 // Install compilation result on the shared function info 1042 InstallSharedCompilationResult(&info, shared); 1043 1044 // Record the function compilation event. 1045 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, &info); 1046 1047 return info.code(); 1048 } 1049 1050 MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) { 1051 Isolate* isolate = function->GetIsolate(); 1052 DCHECK(!isolate->has_pending_exception()); 1053 DCHECK(!function->is_compiled()); 1054 TimerEventScope<TimerEventCompileCode> compile_timer(isolate); 1055 RuntimeCallTimerScope runtimeTimer(isolate, 1056 &RuntimeCallStats::CompileFunction); 1057 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode"); 1058 AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy()); 1059 1060 Handle<Code> cached_code; 1061 if (GetCodeFromOptimizedCodeMap(function, BailoutId::None()) 1062 .ToHandle(&cached_code)) { 1063 if (FLAG_trace_opt) { 1064 PrintF("[found optimized code for "); 1065 function->ShortPrint(); 1066 PrintF(" during unoptimized compile]\n"); 1067 } 1068 DCHECK(function->shared()->is_compiled()); 1069 return cached_code; 1070 } 1071 1072 if (function->shared()->is_compiled() && 1073 function->shared()->marked_for_tier_up()) { 1074 DCHECK(FLAG_mark_shared_functions_for_tier_up); 1075 1076 function->shared()->set_marked_for_tier_up(false); 1077 1078 switch (Compiler::NextCompilationTier(*function)) { 1079 case Compiler::BASELINE: { 1080 // We don't try to handle baseline here because GetBaselineCode() 1081 // doesn't handle top-level code. We aren't supporting 1082 // the hybrid pipeline going forward (where Ignition is a first 1083 // tier followed by full-code). 1084 break; 1085 } 1086 case Compiler::OPTIMIZED: { 1087 if (FLAG_trace_opt) { 1088 PrintF("[optimizing method "); 1089 function->ShortPrint(); 1090 PrintF(" eagerly (shared function marked for tier up)]\n"); 1091 } 1092 1093 Handle<Code> code; 1094 // TODO(leszeks): Look into performing this compilation concurrently. 1095 if (GetOptimizedCode(function, Compiler::NOT_CONCURRENT) 1096 .ToHandle(&code)) { 1097 return code; 1098 } 1099 break; 1100 } 1101 default: 1102 UNREACHABLE(); 1103 } 1104 } 1105 1106 if (function->shared()->is_compiled()) { 1107 return Handle<Code>(function->shared()->code()); 1108 } 1109 1110 if (function->shared()->HasBytecodeArray()) { 1111 Handle<Code> entry = isolate->builtins()->InterpreterEntryTrampoline(); 1112 function->shared()->ReplaceCode(*entry); 1113 return entry; 1114 } 1115 1116 ParseInfo parse_info(handle(function->shared())); 1117 Zone compile_zone(isolate->allocator(), ZONE_NAME); 1118 CompilationInfo info(&compile_zone, &parse_info, function); 1119 Handle<Code> result; 1120 ASSIGN_RETURN_ON_EXCEPTION( 1121 isolate, result, GetUnoptimizedCode(&info, Compiler::CONCURRENT), Code); 1122 1123 if (FLAG_always_opt && !info.shared_info()->HasAsmWasmData()) { 1124 Handle<Code> opt_code; 1125 if (GetOptimizedCode(function, Compiler::NOT_CONCURRENT) 1126 .ToHandle(&opt_code)) { 1127 result = opt_code; 1128 } 1129 } 1130 1131 return result; 1132 } 1133 1134 1135 Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { 1136 Isolate* isolate = info->isolate(); 1137 TimerEventScope<TimerEventCompileCode> timer(isolate); 1138 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode"); 1139 PostponeInterruptsScope postpone(isolate); 1140 DCHECK(!isolate->native_context().is_null()); 1141 ParseInfo* parse_info = info->parse_info(); 1142 1143 RuntimeCallTimerScope runtimeTimer( 1144 isolate, parse_info->is_eval() ? &RuntimeCallStats::CompileEval 1145 : &RuntimeCallStats::CompileScript); 1146 1147 Handle<Script> script = parse_info->script(); 1148 1149 // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile? 1150 FixedArray* array = isolate->native_context()->embedder_data(); 1151 script->set_context_data(array->get(v8::Context::kDebugIdIndex)); 1152 1153 Handle<SharedFunctionInfo> result; 1154 1155 { VMState<COMPILER> state(info->isolate()); 1156 if (parse_info->literal() == nullptr) { 1157 if (!parsing::ParseProgram(parse_info, false)) { 1158 return Handle<SharedFunctionInfo>::null(); 1159 } 1160 1161 { 1162 ParseHandleScope parse_handles(parse_info); 1163 parse_info->ReopenHandlesInNewHandleScope(); 1164 parse_info->ast_value_factory()->Internalize(info->isolate()); 1165 } 1166 } 1167 1168 EnsureSharedFunctionInfosArrayOnScript(parse_info); 1169 1170 // Measure how long it takes to do the compilation; only take the 1171 // rest of the function into account to avoid overlap with the 1172 // parsing statistics. 1173 HistogramTimer* rate = parse_info->is_eval() 1174 ? info->isolate()->counters()->compile_eval() 1175 : info->isolate()->counters()->compile(); 1176 HistogramTimerScope timer(rate); 1177 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 1178 parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile"); 1179 1180 // Allocate a shared function info object. 1181 FunctionLiteral* lit = parse_info->literal(); 1182 DCHECK_EQ(kNoSourcePosition, lit->function_token_position()); 1183 result = isolate->factory()->NewSharedFunctionInfoForLiteral(lit, script); 1184 result->set_is_toplevel(true); 1185 parse_info->set_shared_info(result); 1186 parse_info->set_function_literal_id(result->function_literal_id()); 1187 1188 // Compile the code. 1189 if (!CompileUnoptimizedCode(info, Compiler::CONCURRENT)) { 1190 return Handle<SharedFunctionInfo>::null(); 1191 } 1192 1193 Handle<String> script_name = 1194 script->name()->IsString() 1195 ? Handle<String>(String::cast(script->name())) 1196 : isolate->factory()->empty_string(); 1197 CodeEventListener::LogEventsAndTags log_tag = 1198 parse_info->is_eval() 1199 ? CodeEventListener::EVAL_TAG 1200 : Logger::ToNativeByScript(CodeEventListener::SCRIPT_TAG, *script); 1201 1202 PROFILE(isolate, CodeCreateEvent(log_tag, result->abstract_code(), *result, 1203 *script_name)); 1204 1205 if (!script.is_null()) 1206 script->set_compilation_state(Script::COMPILATION_STATE_COMPILED); 1207 } 1208 1209 return result; 1210 } 1211 1212 } // namespace 1213 1214 // ---------------------------------------------------------------------------- 1215 // Implementation of Compiler 1216 1217 bool Compiler::Analyze(ParseInfo* info, 1218 EagerInnerFunctionLiterals* eager_literals) { 1219 DCHECK_NOT_NULL(info->literal()); 1220 RuntimeCallTimerScope runtimeTimer(info->isolate(), 1221 &RuntimeCallStats::CompileAnalyse); 1222 if (!Rewriter::Rewrite(info)) return false; 1223 DeclarationScope::Analyze(info, AnalyzeMode::kRegular); 1224 if (!Renumber(info, eager_literals)) { 1225 return false; 1226 } 1227 DCHECK_NOT_NULL(info->scope()); 1228 return true; 1229 } 1230 1231 bool Compiler::ParseAndAnalyze(ParseInfo* info) { 1232 if (!parsing::ParseAny(info)) return false; 1233 if (info->is_toplevel()) EnsureSharedFunctionInfosArrayOnScript(info); 1234 if (!Compiler::Analyze(info)) return false; 1235 DCHECK_NOT_NULL(info->literal()); 1236 DCHECK_NOT_NULL(info->scope()); 1237 return true; 1238 } 1239 1240 bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) { 1241 if (function->is_compiled()) return true; 1242 Isolate* isolate = function->GetIsolate(); 1243 DCHECK(AllowCompilation::IsAllowed(isolate)); 1244 1245 CompilerDispatcher* dispatcher = isolate->compiler_dispatcher(); 1246 Handle<SharedFunctionInfo> shared(function->shared(), isolate); 1247 Handle<Code> code; 1248 if (dispatcher->IsEnqueued(shared)) { 1249 if (!dispatcher->FinishNow(shared)) { 1250 if (flag == CLEAR_EXCEPTION) { 1251 isolate->clear_pending_exception(); 1252 } 1253 return false; 1254 } 1255 code = handle(shared->code(), isolate); 1256 } else { 1257 // Start a compilation. 1258 if (!GetLazyCode(function).ToHandle(&code)) { 1259 if (flag == CLEAR_EXCEPTION) { 1260 isolate->clear_pending_exception(); 1261 } 1262 return false; 1263 } 1264 } 1265 1266 // Install code on closure. 1267 function->ReplaceCode(*code); 1268 JSFunction::EnsureLiterals(function); 1269 1270 // Check postconditions on success. 1271 DCHECK(!isolate->has_pending_exception()); 1272 DCHECK(function->shared()->is_compiled()); 1273 DCHECK(function->is_compiled()); 1274 return true; 1275 } 1276 1277 bool Compiler::CompileBaseline(Handle<JSFunction> function) { 1278 Isolate* isolate = function->GetIsolate(); 1279 DCHECK(AllowCompilation::IsAllowed(isolate)); 1280 1281 // Start a compilation. 1282 Handle<Code> code; 1283 if (!GetBaselineCode(function).ToHandle(&code)) { 1284 // Baseline generation failed, get unoptimized code. 1285 DCHECK(function->shared()->is_compiled()); 1286 code = handle(function->shared()->code()); 1287 isolate->clear_pending_exception(); 1288 } 1289 1290 // Install code on closure. 1291 function->ReplaceCode(*code); 1292 JSFunction::EnsureLiterals(function); 1293 1294 // Check postconditions on success. 1295 DCHECK(!isolate->has_pending_exception()); 1296 DCHECK(function->shared()->is_compiled()); 1297 DCHECK(function->is_compiled()); 1298 return true; 1299 } 1300 1301 bool Compiler::CompileOptimized(Handle<JSFunction> function, 1302 ConcurrencyMode mode) { 1303 if (function->IsOptimized()) return true; 1304 Isolate* isolate = function->GetIsolate(); 1305 DCHECK(AllowCompilation::IsAllowed(isolate)); 1306 1307 // Start a compilation. 1308 Handle<Code> code; 1309 if (!GetOptimizedCode(function, mode).ToHandle(&code)) { 1310 // Optimization failed, get unoptimized code. Unoptimized code must exist 1311 // already if we are optimizing. 1312 DCHECK(!isolate->has_pending_exception()); 1313 DCHECK(function->shared()->is_compiled()); 1314 code = handle(function->shared()->code(), isolate); 1315 } 1316 1317 // Install code on closure. 1318 function->ReplaceCode(*code); 1319 JSFunction::EnsureLiterals(function); 1320 1321 // Check postconditions on success. 1322 DCHECK(!isolate->has_pending_exception()); 1323 DCHECK(function->shared()->is_compiled()); 1324 DCHECK(function->is_compiled()); 1325 return true; 1326 } 1327 1328 bool Compiler::CompileDebugCode(Handle<SharedFunctionInfo> shared) { 1329 Isolate* isolate = shared->GetIsolate(); 1330 DCHECK(AllowCompilation::IsAllowed(isolate)); 1331 1332 // Start a compilation. 1333 ParseInfo parse_info(shared); 1334 CompilationInfo info(parse_info.zone(), &parse_info, 1335 Handle<JSFunction>::null()); 1336 info.MarkAsDebug(); 1337 if (GetUnoptimizedCode(&info, Compiler::NOT_CONCURRENT).is_null()) { 1338 isolate->clear_pending_exception(); 1339 return false; 1340 } 1341 1342 // Check postconditions on success. 1343 DCHECK(!isolate->has_pending_exception()); 1344 DCHECK(shared->is_compiled()); 1345 DCHECK(shared->HasDebugCode()); 1346 return true; 1347 } 1348 1349 MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) { 1350 Isolate* isolate = script->GetIsolate(); 1351 DCHECK(AllowCompilation::IsAllowed(isolate)); 1352 1353 // In order to ensure that live edit function info collection finds the newly 1354 // generated shared function infos, clear the script's list temporarily 1355 // and restore it at the end of this method. 1356 Handle<FixedArray> old_function_infos(script->shared_function_infos(), 1357 isolate); 1358 script->set_shared_function_infos(isolate->heap()->empty_fixed_array()); 1359 1360 // Start a compilation. 1361 ParseInfo parse_info(script); 1362 Zone compile_zone(isolate->allocator(), ZONE_NAME); 1363 CompilationInfo info(&compile_zone, &parse_info, Handle<JSFunction>::null()); 1364 info.MarkAsDebug(); 1365 1366 // TODO(635): support extensions. 1367 const bool compilation_succeeded = !CompileToplevel(&info).is_null(); 1368 Handle<JSArray> infos; 1369 if (compilation_succeeded) { 1370 // Check postconditions on success. 1371 DCHECK(!isolate->has_pending_exception()); 1372 infos = LiveEditFunctionTracker::Collect(parse_info.literal(), script, 1373 parse_info.zone(), isolate); 1374 } 1375 1376 // Restore the original function info list in order to remain side-effect 1377 // free as much as possible, since some code expects the old shared function 1378 // infos to stick around. 1379 script->set_shared_function_infos(*old_function_infos); 1380 1381 return infos; 1382 } 1383 1384 bool Compiler::EnsureBytecode(CompilationInfo* info) { 1385 if (!info->shared_info()->is_compiled()) { 1386 CompilerDispatcher* dispatcher = info->isolate()->compiler_dispatcher(); 1387 if (dispatcher->IsEnqueued(info->shared_info())) { 1388 if (!dispatcher->FinishNow(info->shared_info())) return false; 1389 } else if (GetUnoptimizedCode(info, Compiler::NOT_CONCURRENT).is_null()) { 1390 return false; 1391 } 1392 } 1393 DCHECK(info->shared_info()->is_compiled()); 1394 1395 if (info->shared_info()->HasAsmWasmData()) return false; 1396 1397 DCHECK_EQ(ShouldUseIgnition(info), info->shared_info()->HasBytecodeArray()); 1398 return info->shared_info()->HasBytecodeArray(); 1399 } 1400 1401 // TODO(turbofan): In the future, unoptimized code with deopt support could 1402 // be generated lazily once deopt is triggered. 1403 bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) { 1404 DCHECK_NOT_NULL(info->literal()); 1405 DCHECK_NOT_NULL(info->scope()); 1406 Handle<SharedFunctionInfo> shared = info->shared_info(); 1407 1408 CompilerDispatcher* dispatcher = info->isolate()->compiler_dispatcher(); 1409 if (dispatcher->IsEnqueued(shared)) { 1410 if (!dispatcher->FinishNow(shared)) return false; 1411 } 1412 1413 if (!shared->has_deoptimization_support()) { 1414 Zone compile_zone(info->isolate()->allocator(), ZONE_NAME); 1415 CompilationInfo unoptimized(&compile_zone, info->parse_info(), 1416 info->closure()); 1417 unoptimized.EnableDeoptimizationSupport(); 1418 1419 // Don't generate full-codegen code for functions it can't support. 1420 if (shared->must_use_ignition_turbo()) return false; 1421 DCHECK(!IsResumableFunction(shared->kind())); 1422 1423 // When we call PrepareForSerializing below, we will change the shared 1424 // ParseInfo. Make sure to reset it. 1425 bool old_will_serialize_value = info->parse_info()->will_serialize(); 1426 1427 // If the current code has reloc info for serialization, also include 1428 // reloc info for serialization for the new code, so that deopt support 1429 // can be added without losing IC state. 1430 if (shared->code()->kind() == Code::FUNCTION && 1431 shared->code()->has_reloc_info_for_serialization()) { 1432 unoptimized.PrepareForSerializing(); 1433 } 1434 EnsureFeedbackMetadata(&unoptimized); 1435 1436 // Ensure we generate and install bytecode first if the function should use 1437 // Ignition to avoid implicit tier-down. 1438 if (!shared->is_compiled() && ShouldUseIgnition(info) && 1439 !GenerateUnoptimizedCode(info)) { 1440 return false; 1441 } 1442 1443 if (!FullCodeGenerator::MakeCode(&unoptimized)) return false; 1444 1445 info->parse_info()->set_will_serialize(old_will_serialize_value); 1446 1447 // The scope info might not have been set if a lazily compiled 1448 // function is inlined before being called for the first time. 1449 if (shared->scope_info() == ScopeInfo::Empty(info->isolate())) { 1450 InstallSharedScopeInfo(info, shared); 1451 } 1452 1453 // Install compilation result on the shared function info 1454 shared->EnableDeoptimizationSupport(*unoptimized.code()); 1455 1456 // The existing unoptimized code was replaced with the new one. 1457 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, 1458 &unoptimized); 1459 } 1460 return true; 1461 } 1462 1463 // static 1464 Compiler::CompilationTier Compiler::NextCompilationTier(JSFunction* function) { 1465 Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate()); 1466 if (shared->IsInterpreted()) { 1467 if (UseTurboFan(shared)) { 1468 return OPTIMIZED; 1469 } else { 1470 return BASELINE; 1471 } 1472 } else { 1473 return OPTIMIZED; 1474 } 1475 } 1476 1477 MaybeHandle<JSFunction> Compiler::GetFunctionFromEval( 1478 Handle<String> source, Handle<SharedFunctionInfo> outer_info, 1479 Handle<Context> context, LanguageMode language_mode, 1480 ParseRestriction restriction, int parameters_end_pos, 1481 int eval_scope_position, int eval_position, int line_offset, 1482 int column_offset, Handle<Object> script_name, 1483 ScriptOriginOptions options) { 1484 Isolate* isolate = source->GetIsolate(); 1485 int source_length = source->length(); 1486 isolate->counters()->total_eval_size()->Increment(source_length); 1487 isolate->counters()->total_compile_size()->Increment(source_length); 1488 1489 // The cache lookup key needs to be aware of the separation between the 1490 // parameters and the body to prevent this valid invocation: 1491 // Function("", "function anonymous(\n/**/) {\n}"); 1492 // from adding an entry that falsely approves this invalid invocation: 1493 // Function("\n/**/) {\nfunction anonymous(", "}"); 1494 // The actual eval_scope_position for indirect eval and CreateDynamicFunction 1495 // is unused (just 0), which means it's an available field to use to indicate 1496 // this separation. But to make sure we're not causing other false hits, we 1497 // negate the scope position. 1498 int position = eval_scope_position; 1499 if (FLAG_harmony_function_tostring && 1500 restriction == ONLY_SINGLE_FUNCTION_LITERAL && 1501 parameters_end_pos != kNoSourcePosition) { 1502 // use the parameters_end_pos as the eval_scope_position in the eval cache. 1503 DCHECK_EQ(eval_scope_position, 0); 1504 position = -parameters_end_pos; 1505 } 1506 CompilationCache* compilation_cache = isolate->compilation_cache(); 1507 InfoVectorPair eval_result = compilation_cache->LookupEval( 1508 source, outer_info, context, language_mode, position); 1509 Handle<SharedFunctionInfo> shared_info; 1510 if (eval_result.has_shared()) { 1511 shared_info = Handle<SharedFunctionInfo>(eval_result.shared(), isolate); 1512 } 1513 Handle<Cell> vector; 1514 if (eval_result.has_vector()) { 1515 vector = Handle<Cell>(eval_result.vector(), isolate); 1516 } 1517 1518 Handle<Script> script; 1519 if (!eval_result.has_shared()) { 1520 script = isolate->factory()->NewScript(source); 1521 if (isolate->NeedsSourcePositionsForProfiling()) { 1522 Script::InitLineEnds(script); 1523 } 1524 if (!script_name.is_null()) { 1525 script->set_name(*script_name); 1526 script->set_line_offset(line_offset); 1527 script->set_column_offset(column_offset); 1528 } 1529 script->set_origin_options(options); 1530 script->set_compilation_type(Script::COMPILATION_TYPE_EVAL); 1531 Script::SetEvalOrigin(script, outer_info, eval_position); 1532 1533 ParseInfo parse_info(script); 1534 Zone compile_zone(isolate->allocator(), ZONE_NAME); 1535 CompilationInfo info(&compile_zone, &parse_info, 1536 Handle<JSFunction>::null()); 1537 parse_info.set_eval(); 1538 parse_info.set_language_mode(language_mode); 1539 parse_info.set_parse_restriction(restriction); 1540 parse_info.set_parameters_end_pos(parameters_end_pos); 1541 if (!context->IsNativeContext()) { 1542 parse_info.set_outer_scope_info(handle(context->scope_info())); 1543 } 1544 1545 shared_info = CompileToplevel(&info); 1546 if (shared_info.is_null()) { 1547 return MaybeHandle<JSFunction>(); 1548 } 1549 } 1550 1551 // If caller is strict mode, the result must be in strict mode as well. 1552 DCHECK(is_sloppy(language_mode) || is_strict(shared_info->language_mode())); 1553 1554 Handle<JSFunction> result; 1555 if (eval_result.has_shared()) { 1556 if (eval_result.has_vector()) { 1557 result = isolate->factory()->NewFunctionFromSharedFunctionInfo( 1558 shared_info, context, vector, NOT_TENURED); 1559 } else { 1560 result = isolate->factory()->NewFunctionFromSharedFunctionInfo( 1561 shared_info, context, NOT_TENURED); 1562 JSFunction::EnsureLiterals(result); 1563 // Make sure to cache this result. 1564 Handle<Cell> new_vector(result->feedback_vector_cell(), isolate); 1565 compilation_cache->PutEval(source, outer_info, context, shared_info, 1566 new_vector, eval_scope_position); 1567 } 1568 } else { 1569 result = isolate->factory()->NewFunctionFromSharedFunctionInfo( 1570 shared_info, context, NOT_TENURED); 1571 JSFunction::EnsureLiterals(result); 1572 // Add the SharedFunctionInfo and the LiteralsArray to the eval cache if 1573 // we didn't retrieve from there. 1574 Handle<Cell> vector(result->feedback_vector_cell(), isolate); 1575 compilation_cache->PutEval(source, outer_info, context, shared_info, vector, 1576 eval_scope_position); 1577 } 1578 1579 // OnAfterCompile has to be called after we create the JSFunction, which we 1580 // may require to recompile the eval for debugging, if we find a function 1581 // that contains break points in the eval script. 1582 isolate->debug()->OnAfterCompile(script); 1583 1584 return result; 1585 } 1586 1587 namespace { 1588 1589 bool CodeGenerationFromStringsAllowed(Isolate* isolate, 1590 Handle<Context> context) { 1591 DCHECK(context->allow_code_gen_from_strings()->IsFalse(isolate)); 1592 // Check with callback if set. 1593 AllowCodeGenerationFromStringsCallback callback = 1594 isolate->allow_code_gen_callback(); 1595 if (callback == NULL) { 1596 // No callback set and code generation disallowed. 1597 return false; 1598 } else { 1599 // Callback set. Let it decide if code generation is allowed. 1600 VMState<EXTERNAL> state(isolate); 1601 return callback(v8::Utils::ToLocal(context)); 1602 } 1603 } 1604 1605 bool ContainsAsmModule(Handle<Script> script) { 1606 DisallowHeapAllocation no_gc; 1607 SharedFunctionInfo::ScriptIterator iter(script); 1608 while (SharedFunctionInfo* info = iter.Next()) { 1609 if (info->HasAsmWasmData()) return true; 1610 } 1611 return false; 1612 } 1613 1614 } // namespace 1615 1616 MaybeHandle<JSFunction> Compiler::GetFunctionFromString( 1617 Handle<Context> context, Handle<String> source, 1618 ParseRestriction restriction, int parameters_end_pos) { 1619 Isolate* const isolate = context->GetIsolate(); 1620 Handle<Context> native_context(context->native_context(), isolate); 1621 1622 // Check if native context allows code generation from 1623 // strings. Throw an exception if it doesn't. 1624 if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) && 1625 !CodeGenerationFromStringsAllowed(isolate, native_context)) { 1626 Handle<Object> error_message = 1627 native_context->ErrorMessageForCodeGenerationFromStrings(); 1628 THROW_NEW_ERROR(isolate, NewEvalError(MessageTemplate::kCodeGenFromStrings, 1629 error_message), 1630 JSFunction); 1631 } 1632 1633 // Compile source string in the native context. 1634 int eval_scope_position = 0; 1635 int eval_position = kNoSourcePosition; 1636 Handle<SharedFunctionInfo> outer_info(native_context->closure()->shared()); 1637 return Compiler::GetFunctionFromEval(source, outer_info, native_context, 1638 SLOPPY, restriction, parameters_end_pos, 1639 eval_scope_position, eval_position); 1640 } 1641 1642 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript( 1643 Handle<String> source, Handle<Object> script_name, int line_offset, 1644 int column_offset, ScriptOriginOptions resource_options, 1645 Handle<Object> source_map_url, Handle<Context> context, 1646 v8::Extension* extension, ScriptData** cached_data, 1647 ScriptCompiler::CompileOptions compile_options, NativesFlag natives) { 1648 Isolate* isolate = source->GetIsolate(); 1649 if (compile_options == ScriptCompiler::kNoCompileOptions) { 1650 cached_data = NULL; 1651 } else if (compile_options == ScriptCompiler::kProduceParserCache || 1652 compile_options == ScriptCompiler::kProduceCodeCache) { 1653 DCHECK(cached_data && !*cached_data); 1654 DCHECK(extension == NULL); 1655 DCHECK(!isolate->debug()->is_loaded()); 1656 } else { 1657 DCHECK(compile_options == ScriptCompiler::kConsumeParserCache || 1658 compile_options == ScriptCompiler::kConsumeCodeCache); 1659 DCHECK(cached_data && *cached_data); 1660 DCHECK(extension == NULL); 1661 } 1662 int source_length = source->length(); 1663 isolate->counters()->total_load_size()->Increment(source_length); 1664 isolate->counters()->total_compile_size()->Increment(source_length); 1665 1666 LanguageMode language_mode = construct_language_mode(FLAG_use_strict); 1667 CompilationCache* compilation_cache = isolate->compilation_cache(); 1668 1669 // Do a lookup in the compilation cache but not for extensions. 1670 Handle<SharedFunctionInfo> result; 1671 Handle<Cell> vector; 1672 if (extension == NULL) { 1673 // First check per-isolate compilation cache. 1674 InfoVectorPair pair = compilation_cache->LookupScript( 1675 source, script_name, line_offset, column_offset, resource_options, 1676 context, language_mode); 1677 if (!pair.has_shared() && FLAG_serialize_toplevel && 1678 compile_options == ScriptCompiler::kConsumeCodeCache && 1679 !isolate->debug()->is_loaded()) { 1680 // Then check cached code provided by embedder. 1681 HistogramTimerScope timer(isolate->counters()->compile_deserialize()); 1682 RuntimeCallTimerScope runtimeTimer(isolate, 1683 &RuntimeCallStats::CompileDeserialize); 1684 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 1685 "V8.CompileDeserialize"); 1686 Handle<SharedFunctionInfo> inner_result; 1687 if (CodeSerializer::Deserialize(isolate, *cached_data, source) 1688 .ToHandle(&inner_result)) { 1689 // Promote to per-isolate compilation cache. 1690 // TODO(mvstanton): create a feedback vector array here. 1691 DCHECK(inner_result->is_compiled()); 1692 Handle<FeedbackVector> feedback_vector = 1693 FeedbackVector::New(isolate, inner_result); 1694 vector = isolate->factory()->NewCell(feedback_vector); 1695 compilation_cache->PutScript(source, context, language_mode, 1696 inner_result, vector); 1697 return inner_result; 1698 } 1699 // Deserializer failed. Fall through to compile. 1700 } else { 1701 if (pair.has_shared()) { 1702 result = Handle<SharedFunctionInfo>(pair.shared(), isolate); 1703 } 1704 if (pair.has_vector()) { 1705 vector = Handle<Cell>(pair.vector(), isolate); 1706 } 1707 } 1708 } 1709 1710 base::ElapsedTimer timer; 1711 if (FLAG_profile_deserialization && FLAG_serialize_toplevel && 1712 compile_options == ScriptCompiler::kProduceCodeCache) { 1713 timer.Start(); 1714 } 1715 1716 if (result.is_null() || 1717 (FLAG_serialize_toplevel && 1718 compile_options == ScriptCompiler::kProduceCodeCache)) { 1719 // No cache entry found, or embedder wants a code cache. Compile the script. 1720 1721 // Create a script object describing the script to be compiled. 1722 Handle<Script> script = isolate->factory()->NewScript(source); 1723 if (isolate->NeedsSourcePositionsForProfiling()) { 1724 Script::InitLineEnds(script); 1725 } 1726 if (natives == NATIVES_CODE) { 1727 script->set_type(Script::TYPE_NATIVE); 1728 } else if (natives == EXTENSION_CODE) { 1729 script->set_type(Script::TYPE_EXTENSION); 1730 } else if (natives == INSPECTOR_CODE) { 1731 script->set_type(Script::TYPE_INSPECTOR); 1732 } 1733 if (!script_name.is_null()) { 1734 script->set_name(*script_name); 1735 script->set_line_offset(line_offset); 1736 script->set_column_offset(column_offset); 1737 } 1738 script->set_origin_options(resource_options); 1739 if (!source_map_url.is_null()) { 1740 script->set_source_mapping_url(*source_map_url); 1741 } 1742 1743 // Compile the function and add it to the cache. 1744 ParseInfo parse_info(script); 1745 Zone compile_zone(isolate->allocator(), ZONE_NAME); 1746 CompilationInfo info(&compile_zone, &parse_info, 1747 Handle<JSFunction>::null()); 1748 if (resource_options.IsModule()) parse_info.set_module(); 1749 if (compile_options != ScriptCompiler::kNoCompileOptions) { 1750 parse_info.set_cached_data(cached_data); 1751 } 1752 parse_info.set_compile_options(compile_options); 1753 parse_info.set_extension(extension); 1754 if (!context->IsNativeContext()) { 1755 parse_info.set_outer_scope_info(handle(context->scope_info())); 1756 } 1757 if (FLAG_serialize_toplevel && 1758 compile_options == ScriptCompiler::kProduceCodeCache) { 1759 info.PrepareForSerializing(); 1760 } 1761 1762 parse_info.set_language_mode( 1763 static_cast<LanguageMode>(parse_info.language_mode() | language_mode)); 1764 result = CompileToplevel(&info); 1765 if (extension == NULL && !result.is_null()) { 1766 // We need a feedback vector. 1767 DCHECK(result->is_compiled()); 1768 Handle<FeedbackVector> feedback_vector = 1769 FeedbackVector::New(isolate, result); 1770 vector = isolate->factory()->NewCell(feedback_vector); 1771 compilation_cache->PutScript(source, context, language_mode, result, 1772 vector); 1773 if (FLAG_serialize_toplevel && 1774 compile_options == ScriptCompiler::kProduceCodeCache && 1775 !ContainsAsmModule(script)) { 1776 HistogramTimerScope histogram_timer( 1777 isolate->counters()->compile_serialize()); 1778 RuntimeCallTimerScope runtimeTimer(isolate, 1779 &RuntimeCallStats::CompileSerialize); 1780 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), 1781 "V8.CompileSerialize"); 1782 *cached_data = CodeSerializer::Serialize(isolate, result, source); 1783 if (FLAG_profile_deserialization) { 1784 PrintF("[Compiling and serializing took %0.3f ms]\n", 1785 timer.Elapsed().InMillisecondsF()); 1786 } 1787 } 1788 } 1789 1790 if (result.is_null()) { 1791 if (natives != EXTENSION_CODE && natives != NATIVES_CODE) { 1792 isolate->ReportPendingMessages(); 1793 } 1794 } else { 1795 isolate->debug()->OnAfterCompile(script); 1796 } 1797 } else if (result->ic_age() != isolate->heap()->global_ic_age()) { 1798 result->ResetForNewContext(isolate->heap()->global_ic_age()); 1799 } 1800 return result; 1801 } 1802 1803 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForStreamedScript( 1804 Handle<Script> script, ParseInfo* parse_info, int source_length) { 1805 Isolate* isolate = script->GetIsolate(); 1806 // TODO(titzer): increment the counters in caller. 1807 isolate->counters()->total_load_size()->Increment(source_length); 1808 isolate->counters()->total_compile_size()->Increment(source_length); 1809 1810 LanguageMode language_mode = construct_language_mode(FLAG_use_strict); 1811 parse_info->set_language_mode( 1812 static_cast<LanguageMode>(parse_info->language_mode() | language_mode)); 1813 1814 Zone compile_zone(isolate->allocator(), ZONE_NAME); 1815 CompilationInfo compile_info(&compile_zone, parse_info, 1816 Handle<JSFunction>::null()); 1817 1818 // The source was parsed lazily, so compiling for debugging is not possible. 1819 DCHECK(!compile_info.is_debug()); 1820 1821 Handle<SharedFunctionInfo> result = CompileToplevel(&compile_info); 1822 if (!result.is_null()) isolate->debug()->OnAfterCompile(script); 1823 return result; 1824 } 1825 1826 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( 1827 FunctionLiteral* literal, Handle<Script> script, 1828 CompilationInfo* outer_info) { 1829 // Precondition: code has been parsed and scopes have been analyzed. 1830 Isolate* isolate = outer_info->isolate(); 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 result->set_is_toplevel(false); 1847 Scope* outer_scope = literal->scope()->GetOuterScopeWithContext(); 1848 if (outer_scope) { 1849 result->set_outer_scope_info(*outer_scope->scope_info()); 1850 } 1851 return result; 1852 } 1853 1854 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForNative( 1855 v8::Extension* extension, Handle<String> name) { 1856 Isolate* isolate = name->GetIsolate(); 1857 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 1858 1859 // Compute the function template for the native function. 1860 v8::Local<v8::FunctionTemplate> fun_template = 1861 extension->GetNativeFunctionTemplate(v8_isolate, 1862 v8::Utils::ToLocal(name)); 1863 DCHECK(!fun_template.IsEmpty()); 1864 1865 // Instantiate the function and create a shared function info from it. 1866 Handle<JSFunction> fun = Handle<JSFunction>::cast(Utils::OpenHandle( 1867 *fun_template->GetFunction(v8_isolate->GetCurrentContext()) 1868 .ToLocalChecked())); 1869 Handle<Code> code = Handle<Code>(fun->shared()->code()); 1870 Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub()); 1871 Handle<SharedFunctionInfo> shared = isolate->factory()->NewSharedFunctionInfo( 1872 name, FunctionKind::kNormalFunction, code, 1873 Handle<ScopeInfo>(fun->shared()->scope_info())); 1874 shared->set_outer_scope_info(fun->shared()->outer_scope_info()); 1875 shared->SetConstructStub(*construct_stub); 1876 shared->set_feedback_metadata(fun->shared()->feedback_metadata()); 1877 1878 // Copy the function data to the shared function info. 1879 shared->set_function_data(fun->shared()->function_data()); 1880 int parameters = fun->shared()->internal_formal_parameter_count(); 1881 shared->set_internal_formal_parameter_count(parameters); 1882 1883 return shared; 1884 } 1885 1886 MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function, 1887 BailoutId osr_ast_id, 1888 JavaScriptFrame* osr_frame) { 1889 DCHECK(!osr_ast_id.IsNone()); 1890 DCHECK_NOT_NULL(osr_frame); 1891 return GetOptimizedCode(function, NOT_CONCURRENT, osr_ast_id, osr_frame); 1892 } 1893 1894 CompilationJob* Compiler::PrepareUnoptimizedCompilationJob( 1895 CompilationInfo* info) { 1896 VMState<COMPILER> state(info->isolate()); 1897 std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info)); 1898 if (job->PrepareJob() != CompilationJob::SUCCEEDED) { 1899 return nullptr; 1900 } 1901 return job.release(); 1902 } 1903 1904 bool Compiler::FinalizeCompilationJob(CompilationJob* raw_job) { 1905 // Take ownership of compilation job. Deleting job also tears down the zone. 1906 std::unique_ptr<CompilationJob> job(raw_job); 1907 1908 VMState<COMPILER> state(job->info()->isolate()); 1909 if (job->info()->IsOptimizing()) { 1910 return FinalizeOptimizedCompilationJob(job.get()) == 1911 CompilationJob::SUCCEEDED; 1912 } else { 1913 return FinalizeUnoptimizedCompilationJob(job.get()) == 1914 CompilationJob::SUCCEEDED; 1915 } 1916 } 1917 1918 void Compiler::PostInstantiation(Handle<JSFunction> function, 1919 PretenureFlag pretenure) { 1920 Handle<SharedFunctionInfo> shared(function->shared()); 1921 1922 if (FLAG_always_opt && shared->allows_lazy_compilation() && 1923 !function->shared()->HasAsmWasmData() && 1924 function->shared()->is_compiled()) { 1925 function->MarkForOptimization(); 1926 } 1927 1928 Code* code = shared->SearchOptimizedCodeMap( 1929 function->context()->native_context(), BailoutId::None()); 1930 if (code != nullptr) { 1931 // Caching of optimized code enabled and optimized code found. 1932 DCHECK(!code->marked_for_deoptimization()); 1933 DCHECK(function->shared()->is_compiled()); 1934 function->ReplaceCode(code); 1935 } 1936 1937 if (shared->is_compiled()) { 1938 // TODO(mvstanton): pass pretenure flag to EnsureLiterals. 1939 JSFunction::EnsureLiterals(function); 1940 } 1941 } 1942 1943 } // namespace internal 1944 } // namespace v8 1945