| Index: src/compiler.cc | 
| diff --git a/src/compiler.cc b/src/compiler.cc | 
| index 38c8d69691d54fe0ff936537f893fe46d289f2a1..25d65040f9a0470c3e594385dc9f30ece9ec4148 100644 | 
| --- a/src/compiler.cc | 
| +++ b/src/compiler.cc | 
| @@ -38,8 +38,6 @@ | 
| namespace v8 { | 
| namespace internal { | 
|  | 
| - | 
| - | 
| // A wrapper around a CompilationInfo that detaches the Handles from | 
| // the underlying DeferredHandleScope and stores them in info_ on | 
| // destruction. | 
| @@ -377,8 +375,7 @@ bool ShouldUseIgnition(CompilationInfo* info) { | 
| return shared->PassesFilter(FLAG_ignition_filter); | 
| } | 
|  | 
| -CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info, | 
| -                                             LazyCompilationMode mode) { | 
| +CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) { | 
| // Function should have been parsed and analyzed before creating a compilation | 
| // job. | 
| DCHECK_NOT_NULL(info->literal()); | 
| @@ -386,9 +383,9 @@ CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info, | 
|  | 
| EnsureFeedbackMetadata(info); | 
| if (ShouldUseIgnition(info)) { | 
| -    return interpreter::Interpreter::NewCompilationJob(info, mode); | 
| +    return interpreter::Interpreter::NewCompilationJob(info); | 
| } else { | 
| -    return FullCodeGenerator::NewCompilationJob(info, mode); | 
| +    return FullCodeGenerator::NewCompilationJob(info); | 
| } | 
| } | 
|  | 
| @@ -437,6 +434,28 @@ CompilationJob::Status FinalizeUnoptimizedCompilationJob(CompilationJob* job) { | 
| return status; | 
| } | 
|  | 
| +bool Renumber(ParseInfo* parse_info, | 
| +              Compiler::EagerInnerFunctionLiterals* eager_literals) { | 
| +  RuntimeCallTimerScope runtimeTimer(parse_info->isolate(), | 
| +                                     &RuntimeCallStats::CompileRenumber); | 
| +  if (!AstNumbering::Renumber(parse_info->isolate(), parse_info->zone(), | 
| +                              parse_info->literal(), eager_literals)) { | 
| +    return false; | 
| +  } | 
| +  Handle<SharedFunctionInfo> shared_info = parse_info->shared_info(); | 
| +  if (!shared_info.is_null()) { | 
| +    FunctionLiteral* lit = parse_info->literal(); | 
| +    shared_info->set_ast_node_count(lit->ast_node_count()); | 
| +    if (lit->dont_optimize_reason() != kNoReason) { | 
| +      shared_info->DisableOptimization(lit->dont_optimize_reason()); | 
| +    } | 
| +    if (lit->flags() & AstProperties::kMustUseIgnitionTurbo) { | 
| +      shared_info->set_must_use_ignition_turbo(true); | 
| +    } | 
| +  } | 
| +  return true; | 
| +} | 
| + | 
| bool GenerateUnoptimizedCode(CompilationInfo* info) { | 
| if (FLAG_validate_asm && info->scope()->asm_module() && | 
| !info->shared_info()->is_asm_wasm_broken() && !info->is_debug()) { | 
| @@ -451,8 +470,7 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) { | 
| } | 
| } | 
|  | 
| -  std::unique_ptr<CompilationJob> job( | 
| -      GetUnoptimizedCompilationJob(info, LazyCompilationMode::kIfRequested)); | 
| +  std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info)); | 
| if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false; | 
| if (job->ExecuteJob() != CompilationJob::SUCCEEDED) return false; | 
| if (FinalizeUnoptimizedCompilationJob(job.get()) != | 
| @@ -462,14 +480,76 @@ bool GenerateUnoptimizedCode(CompilationInfo* info) { | 
| return true; | 
| } | 
|  | 
| +bool CompileUnoptimizedInnerFunctionsRecursively( | 
| +    ThreadedList<ThreadedListZoneEntry<FunctionLiteral*>>* literals, | 
| +    CompilationInfo* outer_info) { | 
| +  Isolate* isolate = outer_info->isolate(); | 
| +  Handle<Script> script = outer_info->script(); | 
| +  RuntimeCallTimerScope runtimeTimer(isolate, | 
| +                                     &RuntimeCallStats::CompileInnerFunction); | 
| + | 
| +  for (auto it : *literals) { | 
| +    FunctionLiteral* literal = it->value(); | 
| + | 
| +    // Find any previously allocated shared function info for the given literal. | 
| +    Handle<SharedFunctionInfo> shared; | 
| +    MaybeHandle<SharedFunctionInfo> maybe_existing = | 
| +        script->FindSharedFunctionInfo(isolate, literal); | 
| +    if (maybe_existing.ToHandle(&shared)) { | 
| +      DCHECK(!shared->is_toplevel()); | 
| +      // If we found an existing shared function info with compiled code, | 
| +      // we are done. | 
| +      if (shared->is_compiled()) continue; | 
| +    } else { | 
| +      shared = | 
| +          isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script); | 
| +      shared->set_is_toplevel(false); | 
| +    } | 
| + | 
| +    Zone zone(isolate->allocator(), ZONE_NAME); | 
| +    ParseInfo parse_info(&zone, script); | 
| +    parse_info.set_literal(literal); | 
| +    parse_info.set_shared_info(shared); | 
| +    parse_info.set_function_literal_id(shared->function_literal_id()); | 
| +    parse_info.set_language_mode(literal->scope()->language_mode()); | 
| +    parse_info.set_ast_value_factory( | 
| +        outer_info->parse_info()->ast_value_factory()); | 
| +    parse_info.set_ast_value_factory_owned(false); | 
| + | 
| +    CompilationInfo info(&parse_info, Handle<JSFunction>::null()); | 
| +    if (outer_info->will_serialize()) info.PrepareForSerializing(); | 
| +    if (outer_info->is_debug()) info.MarkAsDebug(); | 
| + | 
| +    Compiler::EagerInnerFunctionLiterals inner_literals; | 
| +    if (!Renumber(&parse_info, &inner_literals) || | 
| +        !CompileUnoptimizedInnerFunctionsRecursively(&inner_literals, | 
| +                                                     outer_info) || | 
| +        !GenerateUnoptimizedCode(&info)) { | 
| +      if (!isolate->has_pending_exception()) isolate->StackOverflow(); | 
| +      return false; | 
| +    } | 
| + | 
| +    DCHECK(!info.code().is_null()); | 
| +    RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, &info); | 
| +    if (literal->should_be_used_once_hint()) { | 
| +      info.code()->MarkToBeExecutedOnce(isolate); | 
| +    } | 
| +  } | 
| +  return true; | 
| +} | 
| + | 
| bool CompileUnoptimizedCode(CompilationInfo* info) { | 
| -  DCHECK(AllowCompilation::IsAllowed(info->isolate())); | 
| -  if (!Compiler::Analyze(info->parse_info()) || | 
| +  Isolate* isolate = info->isolate(); | 
| +  DCHECK(AllowCompilation::IsAllowed(isolate)); | 
| + | 
| +  Compiler::EagerInnerFunctionLiterals inner_literals; | 
| +  if (!Compiler::Analyze(info->parse_info(), &inner_literals) || | 
| +      !CompileUnoptimizedInnerFunctionsRecursively(&inner_literals, info) || | 
| !GenerateUnoptimizedCode(info)) { | 
| -    Isolate* isolate = info->isolate(); | 
| if (!isolate->has_pending_exception()) isolate->StackOverflow(); | 
| return false; | 
| } | 
| + | 
| return true; | 
| } | 
|  | 
| @@ -552,27 +632,6 @@ void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { | 
| literals, info->osr_ast_id()); | 
| } | 
|  | 
| -bool Renumber(ParseInfo* parse_info) { | 
| -  RuntimeCallTimerScope runtimeTimer(parse_info->isolate(), | 
| -                                     &RuntimeCallStats::CompileRenumber); | 
| -  if (!AstNumbering::Renumber(parse_info->isolate(), parse_info->zone(), | 
| -                              parse_info->literal())) { | 
| -    return false; | 
| -  } | 
| -  Handle<SharedFunctionInfo> shared_info = parse_info->shared_info(); | 
| -  if (!shared_info.is_null()) { | 
| -    FunctionLiteral* lit = parse_info->literal(); | 
| -    shared_info->set_ast_node_count(lit->ast_node_count()); | 
| -    if (lit->dont_optimize_reason() != kNoReason) { | 
| -      shared_info->DisableOptimization(lit->dont_optimize_reason()); | 
| -    } | 
| -    if (lit->flags() & AstProperties::kMustUseIgnitionTurbo) { | 
| -      shared_info->set_must_use_ignition_turbo(true); | 
| -    } | 
| -  } | 
| -  return true; | 
| -} | 
| - | 
| bool GetOptimizedCodeNow(CompilationJob* job) { | 
| CompilationInfo* info = job->info(); | 
| Isolate* isolate = info->isolate(); | 
| @@ -1016,8 +1075,6 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { | 
|  | 
| EnsureSharedFunctionInfosArrayOnScript(parse_info); | 
|  | 
| -    FunctionLiteral* lit = parse_info->literal(); | 
| - | 
| // Measure how long it takes to do the compilation; only take the | 
| // rest of the function into account to avoid overlap with the | 
| // parsing statistics. | 
| @@ -1029,6 +1086,7 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { | 
| parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile"); | 
|  | 
| // Allocate a shared function info object. | 
| +    FunctionLiteral* lit = parse_info->literal(); | 
| DCHECK_EQ(kNoSourcePosition, lit->function_token_position()); | 
| result = isolate->factory()->NewSharedFunctionInfoForLiteral(lit, script); | 
| result->set_is_toplevel(true); | 
| @@ -1064,13 +1122,14 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { | 
| // ---------------------------------------------------------------------------- | 
| // Implementation of Compiler | 
|  | 
| -bool Compiler::Analyze(ParseInfo* info) { | 
| +bool Compiler::Analyze(ParseInfo* info, | 
| +                       EagerInnerFunctionLiterals* eager_literals) { | 
| DCHECK_NOT_NULL(info->literal()); | 
| RuntimeCallTimerScope runtimeTimer(info->isolate(), | 
| &RuntimeCallStats::CompileAnalyse); | 
| if (!Rewriter::Rewrite(info)) return false; | 
| DeclarationScope::Analyze(info, AnalyzeMode::kRegular); | 
| -  if (!Renumber(info)) return false; | 
| +  if (!Renumber(info, eager_literals)) return false; | 
| DCHECK_NOT_NULL(info->scope()); | 
| return true; | 
| } | 
| @@ -1592,7 +1651,7 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForStreamedScript( | 
|  | 
| Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( | 
| FunctionLiteral* literal, Handle<Script> script, | 
| -    CompilationInfo* outer_info, LazyCompilationMode mode) { | 
| +    CompilationInfo* outer_info) { | 
| // Precondition: code has been parsed and scopes have been analyzed. | 
| Isolate* isolate = outer_info->isolate(); | 
| MaybeHandle<SharedFunctionInfo> maybe_existing; | 
| @@ -1600,80 +1659,21 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( | 
| // Find any previously allocated shared function info for the given literal. | 
| maybe_existing = script->FindSharedFunctionInfo(isolate, literal); | 
|  | 
| -  // We found an existing shared function info. If it has any sort of code | 
| -  // attached, don't worry about compiling and simply return it. Otherwise, | 
| -  // continue to decide whether to eagerly compile. | 
| -  // Note that we also carry on if we are compiling eager to obtain code for | 
| -  // debugging, unless we already have code with debug break slots. | 
| +  // If we found an existing shared function info, return it. | 
| Handle<SharedFunctionInfo> existing; | 
| if (maybe_existing.ToHandle(&existing)) { | 
| DCHECK(!existing->is_toplevel()); | 
| -    if (existing->HasBaselineCode() || existing->HasBytecodeArray()) { | 
| -      if (!outer_info->is_debug() || existing->HasDebugCode()) { | 
| -        return existing; | 
| -      } | 
| -    } | 
| +    return existing; | 
| } | 
|  | 
| -  // Allocate a shared function info object. | 
| -  Handle<SharedFunctionInfo> result; | 
| -  if (!maybe_existing.ToHandle(&result)) { | 
| -    result = | 
| -        isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script); | 
| -    result->set_is_toplevel(false); | 
| -  } | 
| - | 
| -  Zone zone(isolate->allocator(), ZONE_NAME); | 
| -  ParseInfo parse_info(&zone, script); | 
| -  CompilationInfo info(&parse_info, Handle<JSFunction>::null()); | 
| -  parse_info.set_literal(literal); | 
| -  parse_info.set_shared_info(result); | 
| -  parse_info.set_function_literal_id(result->function_literal_id()); | 
| -  parse_info.set_language_mode(literal->scope()->language_mode()); | 
| -  parse_info.set_ast_value_factory( | 
| -      outer_info->parse_info()->ast_value_factory()); | 
| -  parse_info.set_ast_value_factory_owned(false); | 
| - | 
| -  if (outer_info->will_serialize()) info.PrepareForSerializing(); | 
| -  if (outer_info->is_debug()) info.MarkAsDebug(); | 
| - | 
| -  // If this inner function is already compiled, we don't need to compile | 
| -  // again. When compiling for debug, we are not interested in having debug | 
| -  // break slots in inner functions, neither for setting break points nor | 
| -  // for revealing inner functions. | 
| -  // This is especially important for generators. We must not replace the | 
| -  // code for generators, as there may be suspended generator objects. | 
| -  if (!result->is_compiled()) { | 
| -    if (mode == LazyCompilationMode::kAlways || | 
| -        !literal->ShouldEagerCompile()) { | 
| -      info.SetCode(isolate->builtins()->CompileLazy()); | 
| -      Scope* outer_scope = literal->scope()->GetOuterScopeWithContext(); | 
| -      if (outer_scope) { | 
| -        result->set_outer_scope_info(*outer_scope->scope_info()); | 
| -      } | 
| -    } else { | 
| -      // Generate code | 
| -      TimerEventScope<TimerEventCompileCode> timer(isolate); | 
| -      RuntimeCallTimerScope runtimeTimer( | 
| -          isolate, &RuntimeCallStats::CompileInnerFunction); | 
| -      TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode"); | 
| -      if (Renumber(info.parse_info()) && GenerateUnoptimizedCode(&info)) { | 
| -        // Code generation will ensure that the feedback vector is present and | 
| -        // appropriately sized. | 
| -        DCHECK(!info.code().is_null()); | 
| -        if (literal->should_be_used_once_hint()) { | 
| -          info.code()->MarkToBeExecutedOnce(isolate); | 
| -        } | 
| -      } else { | 
| -        return Handle<SharedFunctionInfo>::null(); | 
| -      } | 
| -    } | 
| -  } | 
| - | 
| -  if (maybe_existing.is_null()) { | 
| -    RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, &info); | 
| +  // Allocate a shared function info object which will be compiled lazily. | 
| +  Handle<SharedFunctionInfo> result = | 
| +      isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script); | 
| +  result->set_is_toplevel(false); | 
| +  Scope* outer_scope = literal->scope()->GetOuterScopeWithContext(); | 
| +  if (outer_scope) { | 
| +    result->set_outer_scope_info(*outer_scope->scope_info()); | 
| } | 
| - | 
| return result; | 
| } | 
|  | 
| @@ -1718,9 +1718,9 @@ MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function, | 
| } | 
|  | 
| CompilationJob* Compiler::PrepareUnoptimizedCompilationJob( | 
| -    CompilationInfo* info, LazyCompilationMode mode) { | 
| +    CompilationInfo* info) { | 
| VMState<COMPILER> state(info->isolate()); | 
| -  std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info, mode)); | 
| +  std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info)); | 
| if (job->PrepareJob() != CompilationJob::SUCCEEDED) { | 
| return nullptr; | 
| } | 
|  |