• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/codegen/compiler.h"
6  
7  #include <algorithm>
8  #include <memory>
9  
10  #include "src/api/api-inl.h"
11  #include "src/asmjs/asm-js.h"
12  #include "src/ast/prettyprinter.h"
13  #include "src/ast/scopes.h"
14  #include "src/base/logging.h"
15  #include "src/base/optional.h"
16  #include "src/codegen/assembler-inl.h"
17  #include "src/codegen/compilation-cache.h"
18  #include "src/codegen/optimized-compilation-info.h"
19  #include "src/codegen/pending-optimization-table.h"
20  #include "src/codegen/unoptimized-compilation-info.h"
21  #include "src/common/assert-scope.h"
22  #include "src/common/globals.h"
23  #include "src/common/message-template.h"
24  #include "src/compiler-dispatcher/compiler-dispatcher.h"
25  #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
26  #include "src/compiler/pipeline.h"
27  #include "src/debug/debug.h"
28  #include "src/debug/liveedit.h"
29  #include "src/diagnostics/code-tracer.h"
30  #include "src/execution/frames-inl.h"
31  #include "src/execution/isolate-inl.h"
32  #include "src/execution/isolate.h"
33  #include "src/execution/runtime-profiler.h"
34  #include "src/execution/vm-state-inl.h"
35  #include "src/handles/maybe-handles.h"
36  #include "src/heap/heap-inl.h"
37  #include "src/heap/local-factory-inl.h"
38  #include "src/heap/local-heap-inl.h"
39  #include "src/heap/local-heap.h"
40  #include "src/init/bootstrapper.h"
41  #include "src/interpreter/interpreter.h"
42  #include "src/logging/log-inl.h"
43  #include "src/objects/feedback-cell-inl.h"
44  #include "src/objects/js-function-inl.h"
45  #include "src/objects/map.h"
46  #include "src/objects/object-list-macros.h"
47  #include "src/objects/shared-function-info.h"
48  #include "src/objects/string.h"
49  #include "src/parsing/parse-info.h"
50  #include "src/parsing/parser.h"
51  #include "src/parsing/parsing.h"
52  #include "src/parsing/pending-compilation-error-handler.h"
53  #include "src/parsing/scanner-character-streams.h"
54  #include "src/snapshot/code-serializer.h"
55  #include "src/utils/ostreams.h"
56  #include "src/zone/zone-list-inl.h"  // crbug.com/v8/8816
57  
58  namespace v8 {
59  namespace internal {
60  
61  namespace {
62  
IsForNativeContextIndependentCachingOnly(CodeKind kind)63  bool IsForNativeContextIndependentCachingOnly(CodeKind kind) {
64    // NCI code is only cached (and not installed on the JSFunction upon
65    // successful compilation), unless the testing-only
66    // FLAG_turbo_nci_as_midtier is enabled.
67    return CodeKindIsNativeContextIndependentJSFunction(kind) &&
68           !FLAG_turbo_nci_as_midtier;
69  }
70  
71  // This predicate is currently needed only because the nci-as-midtier testing
72  // configuration is special. A quick summary of compilation configurations:
73  //
74  // - Turbofan (and currently Turboprop) uses both the optimization marker and
75  // the optimized code cache (underneath, the marker and the cache share the same
76  // slot on the feedback vector).
77  // - Native context independent (NCI) code uses neither the marker nor the
78  // cache.
79  // - The NCI-as-midtier testing configuration uses the marker, but not the
80  // cache.
81  //
82  // This predicate supports that last case. In the near future, this last case is
83  // expected to change s.t. code kinds use the marker iff they use the optimized
84  // code cache (details still TBD). In that case, the existing
85  // CodeKindIsStoredInOptimizedCodeCache is sufficient and this extra predicate
86  // can be removed.
87  // TODO(jgruber,rmcilroy,v8:8888): Remove this predicate once that has happened.
UsesOptimizationMarker(CodeKind kind)88  bool UsesOptimizationMarker(CodeKind kind) {
89    return !IsForNativeContextIndependentCachingOnly(kind);
90  }
91  
92  class CompilerTracer : public AllStatic {
93   public:
PrintTracePrefix(const CodeTracer::Scope & scope,const char * header,OptimizedCompilationInfo * info)94    static void PrintTracePrefix(const CodeTracer::Scope& scope,
95                                 const char* header,
96                                 OptimizedCompilationInfo* info) {
97      PrintTracePrefix(scope, header, info->closure(), info->code_kind());
98    }
99  
PrintTracePrefix(const CodeTracer::Scope & scope,const char * header,Handle<JSFunction> function,CodeKind code_kind)100    static void PrintTracePrefix(const CodeTracer::Scope& scope,
101                                 const char* header, Handle<JSFunction> function,
102                                 CodeKind code_kind) {
103      PrintF(scope.file(), "[%s ", header);
104      function->ShortPrint(scope.file());
105      PrintF(scope.file(), " (target %s)", CodeKindToString(code_kind));
106    }
107  
PrintTraceSuffix(const CodeTracer::Scope & scope)108    static void PrintTraceSuffix(const CodeTracer::Scope& scope) {
109      PrintF(scope.file(), "]\n");
110    }
111  
TracePrepareJob(Isolate * isolate,OptimizedCompilationInfo * info,const char * compiler_name)112    static void TracePrepareJob(Isolate* isolate, OptimizedCompilationInfo* info,
113                                const char* compiler_name) {
114      if (!FLAG_trace_opt || !info->IsOptimizing()) return;
115      CodeTracer::Scope scope(isolate->GetCodeTracer());
116      PrintTracePrefix(scope, "compiling method", info);
117      PrintF(scope.file(), " using %s%s", compiler_name,
118             info->is_osr() ? " OSR" : "");
119      PrintTraceSuffix(scope);
120    }
121  
TraceCompilationStats(Isolate * isolate,OptimizedCompilationInfo * info,double ms_creategraph,double ms_optimize,double ms_codegen)122    static void TraceCompilationStats(Isolate* isolate,
123                                      OptimizedCompilationInfo* info,
124                                      double ms_creategraph, double ms_optimize,
125                                      double ms_codegen) {
126      if (!FLAG_trace_opt || !info->IsOptimizing()) return;
127      CodeTracer::Scope scope(isolate->GetCodeTracer());
128      PrintTracePrefix(scope, "optimizing", info);
129      PrintF(scope.file(), " - took %0.3f, %0.3f, %0.3f ms", ms_creategraph,
130             ms_optimize, ms_codegen);
131      PrintTraceSuffix(scope);
132    }
133  
TraceCompletedJob(Isolate * isolate,OptimizedCompilationInfo * info)134    static void TraceCompletedJob(Isolate* isolate,
135                                  OptimizedCompilationInfo* info) {
136      if (!FLAG_trace_opt) return;
137      CodeTracer::Scope scope(isolate->GetCodeTracer());
138      PrintTracePrefix(scope, "completed optimizing", info);
139      PrintTraceSuffix(scope);
140    }
141  
TraceAbortedJob(Isolate * isolate,OptimizedCompilationInfo * info)142    static void TraceAbortedJob(Isolate* isolate,
143                                OptimizedCompilationInfo* info) {
144      if (!FLAG_trace_opt) return;
145      CodeTracer::Scope scope(isolate->GetCodeTracer());
146      PrintTracePrefix(scope, "aborted optimizing", info);
147      PrintF(scope.file(), " because: %s",
148             GetBailoutReason(info->bailout_reason()));
149      PrintTraceSuffix(scope);
150    }
151  
TraceOptimizedCodeCacheHit(Isolate * isolate,Handle<JSFunction> function,BailoutId osr_offset,CodeKind code_kind)152    static void TraceOptimizedCodeCacheHit(Isolate* isolate,
153                                           Handle<JSFunction> function,
154                                           BailoutId osr_offset,
155                                           CodeKind code_kind) {
156      if (!FLAG_trace_opt) return;
157      CodeTracer::Scope scope(isolate->GetCodeTracer());
158      PrintTracePrefix(scope, "found optimized code for", function, code_kind);
159      if (!osr_offset.IsNone()) {
160        PrintF(scope.file(), " at OSR AST id %d", osr_offset.ToInt());
161      }
162      PrintTraceSuffix(scope);
163    }
164  
TraceOptimizeForAlwaysOpt(Isolate * isolate,Handle<JSFunction> function,CodeKind code_kind)165    static void TraceOptimizeForAlwaysOpt(Isolate* isolate,
166                                          Handle<JSFunction> function,
167                                          CodeKind code_kind) {
168      if (!FLAG_trace_opt) return;
169      CodeTracer::Scope scope(isolate->GetCodeTracer());
170      PrintTracePrefix(scope, "optimizing", function, code_kind);
171      PrintF(scope.file(), " because --always-opt");
172      PrintTraceSuffix(scope);
173    }
174  
TraceMarkForAlwaysOpt(Isolate * isolate,Handle<JSFunction> function)175    static void TraceMarkForAlwaysOpt(Isolate* isolate,
176                                      Handle<JSFunction> function) {
177      if (!FLAG_trace_opt) return;
178      CodeTracer::Scope scope(isolate->GetCodeTracer());
179      PrintF(scope.file(), "[marking ");
180      function->ShortPrint(scope.file());
181      PrintF(scope.file(), " for optimized recompilation because --always-opt");
182      PrintF(scope.file(), "]\n");
183    }
184  };
185  
186  }  // namespace
187  
188  // Helper that times a scoped region and records the elapsed time.
189  struct ScopedTimer {
ScopedTimerv8::internal::ScopedTimer190    explicit ScopedTimer(base::TimeDelta* location) : location_(location) {
191      DCHECK_NOT_NULL(location_);
192      timer_.Start();
193    }
194  
~ScopedTimerv8::internal::ScopedTimer195    ~ScopedTimer() { *location_ += timer_.Elapsed(); }
196  
197    base::ElapsedTimer timer_;
198    base::TimeDelta* location_;
199  };
200  
201  namespace {
202  
LogFunctionCompilation(CodeEventListener::LogEventsAndTags tag,Handle<SharedFunctionInfo> shared,Handle<Script> script,Handle<AbstractCode> abstract_code,bool optimizing,double time_taken_ms,Isolate * isolate)203  void LogFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
204                              Handle<SharedFunctionInfo> shared,
205                              Handle<Script> script,
206                              Handle<AbstractCode> abstract_code, bool optimizing,
207                              double time_taken_ms, Isolate* isolate) {
208    DCHECK(!abstract_code.is_null());
209    DCHECK(!abstract_code.is_identical_to(BUILTIN_CODE(isolate, CompileLazy)));
210  
211    // Log the code generation. If source information is available include
212    // script name and line number. Check explicitly whether logging is
213    // enabled as finding the line number is not free.
214    if (!isolate->logger()->is_listening_to_code_events() &&
215        !isolate->is_profiling() && !FLAG_log_function_events &&
216        !isolate->code_event_dispatcher()->IsListeningToCodeEvents()) {
217      return;
218    }
219  
220    int line_num = Script::GetLineNumber(script, shared->StartPosition()) + 1;
221    int column_num = Script::GetColumnNumber(script, shared->StartPosition()) + 1;
222    Handle<String> script_name(script->name().IsString()
223                                   ? String::cast(script->name())
224                                   : ReadOnlyRoots(isolate).empty_string(),
225                               isolate);
226    CodeEventListener::LogEventsAndTags log_tag =
227        Logger::ToNativeByScript(tag, *script);
228    PROFILE(isolate, CodeCreateEvent(log_tag, abstract_code, shared, script_name,
229                                     line_num, column_num));
230    if (!FLAG_log_function_events) return;
231  
232    DisallowHeapAllocation no_gc;
233  
234    std::string name = optimizing ? "optimize" : "compile";
235    switch (tag) {
236      case CodeEventListener::EVAL_TAG:
237        name += "-eval";
238        break;
239      case CodeEventListener::SCRIPT_TAG:
240        break;
241      case CodeEventListener::LAZY_COMPILE_TAG:
242        name += "-lazy";
243        break;
244      case CodeEventListener::FUNCTION_TAG:
245        break;
246      default:
247        UNREACHABLE();
248    }
249  
250    LOG(isolate, FunctionEvent(name.c_str(), script->id(), time_taken_ms,
251                               shared->StartPosition(), shared->EndPosition(),
252                               shared->DebugName()));
253  }
254  
OriginOptionsForEval(Object script)255  ScriptOriginOptions OriginOptionsForEval(Object script) {
256    if (!script.IsScript()) return ScriptOriginOptions();
257  
258    const auto outer_origin_options = Script::cast(script).origin_options();
259    return ScriptOriginOptions(outer_origin_options.IsSharedCrossOrigin(),
260                               outer_origin_options.IsOpaque());
261  }
262  
263  }  // namespace
264  
265  // ----------------------------------------------------------------------------
266  // Implementation of UnoptimizedCompilationJob
267  
ExecuteJob()268  CompilationJob::Status UnoptimizedCompilationJob::ExecuteJob() {
269    DisallowHeapAccess no_heap_access;
270    // Delegate to the underlying implementation.
271    DCHECK_EQ(state(), State::kReadyToExecute);
272    ScopedTimer t(&time_taken_to_execute_);
273    return UpdateState(ExecuteJobImpl(), State::kReadyToFinalize);
274  }
275  
FinalizeJob(Handle<SharedFunctionInfo> shared_info,Isolate * isolate)276  CompilationJob::Status UnoptimizedCompilationJob::FinalizeJob(
277      Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
278    DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
279    DisallowCodeDependencyChange no_dependency_change;
280    DisallowJavascriptExecution no_js(isolate);
281  
282    // Delegate to the underlying implementation.
283    DCHECK_EQ(state(), State::kReadyToFinalize);
284    ScopedTimer t(&time_taken_to_finalize_);
285    return UpdateState(FinalizeJobImpl(shared_info, isolate), State::kSucceeded);
286  }
287  
FinalizeJob(Handle<SharedFunctionInfo> shared_info,LocalIsolate * isolate)288  CompilationJob::Status UnoptimizedCompilationJob::FinalizeJob(
289      Handle<SharedFunctionInfo> shared_info, LocalIsolate* isolate) {
290    // Delegate to the underlying implementation.
291    DCHECK_EQ(state(), State::kReadyToFinalize);
292    ScopedTimer t(&time_taken_to_finalize_);
293    return UpdateState(FinalizeJobImpl(shared_info, isolate), State::kSucceeded);
294  }
295  
296  namespace {
297  
RecordUnoptimizedCompilationStats(Isolate * isolate,Handle<SharedFunctionInfo> shared_info)298  void RecordUnoptimizedCompilationStats(Isolate* isolate,
299                                         Handle<SharedFunctionInfo> shared_info) {
300    int code_size;
301    if (shared_info->HasBytecodeArray()) {
302      code_size = shared_info->GetBytecodeArray().SizeIncludingMetadata();
303    } else {
304      code_size = shared_info->asm_wasm_data().Size();
305    }
306  
307    Counters* counters = isolate->counters();
308    // TODO(4280): Rename counters from "baseline" to "unoptimized" eventually.
309    counters->total_baseline_code_size()->Increment(code_size);
310    counters->total_baseline_compile_count()->Increment(1);
311  
312    // TODO(5203): Add timers for each phase of compilation.
313    // Also add total time (there's now already timer_ on the base class).
314  }
315  
RecordUnoptimizedFunctionCompilation(Isolate * isolate,CodeEventListener::LogEventsAndTags tag,Handle<SharedFunctionInfo> shared,base::TimeDelta time_taken_to_execute,base::TimeDelta time_taken_to_finalize)316  void RecordUnoptimizedFunctionCompilation(
317      Isolate* isolate, CodeEventListener::LogEventsAndTags tag,
318      Handle<SharedFunctionInfo> shared, base::TimeDelta time_taken_to_execute,
319      base::TimeDelta time_taken_to_finalize) {
320    Handle<AbstractCode> abstract_code;
321    if (shared->HasBytecodeArray()) {
322      abstract_code =
323          handle(AbstractCode::cast(shared->GetBytecodeArray()), isolate);
324    } else {
325      DCHECK(shared->HasAsmWasmData());
326      abstract_code =
327          Handle<AbstractCode>::cast(BUILTIN_CODE(isolate, InstantiateAsmJs));
328    }
329  
330    double time_taken_ms = time_taken_to_execute.InMillisecondsF() +
331                           time_taken_to_finalize.InMillisecondsF();
332  
333    Handle<Script> script(Script::cast(shared->script()), isolate);
334    LogFunctionCompilation(tag, shared, script, abstract_code, false,
335                           time_taken_ms, isolate);
336  }
337  
338  }  // namespace
339  
340  // ----------------------------------------------------------------------------
341  // Implementation of OptimizedCompilationJob
342  
PrepareJob(Isolate * isolate)343  CompilationJob::Status OptimizedCompilationJob::PrepareJob(Isolate* isolate) {
344    DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
345    DisallowJavascriptExecution no_js(isolate);
346    CompilerTracer::TracePrepareJob(isolate, compilation_info(), compiler_name_);
347  
348    // Delegate to the underlying implementation.
349    DCHECK_EQ(state(), State::kReadyToPrepare);
350    ScopedTimer t(&time_taken_to_prepare_);
351    return UpdateState(PrepareJobImpl(isolate), State::kReadyToExecute);
352  }
353  
ExecuteJob(RuntimeCallStats * stats,LocalIsolate * local_isolate)354  CompilationJob::Status OptimizedCompilationJob::ExecuteJob(
355      RuntimeCallStats* stats, LocalIsolate* local_isolate) {
356    DisallowHeapAccess no_heap_access;
357    // Delegate to the underlying implementation.
358    DCHECK_EQ(state(), State::kReadyToExecute);
359    ScopedTimer t(&time_taken_to_execute_);
360    return UpdateState(ExecuteJobImpl(stats, local_isolate),
361                       State::kReadyToFinalize);
362  }
363  
FinalizeJob(Isolate * isolate)364  CompilationJob::Status OptimizedCompilationJob::FinalizeJob(Isolate* isolate) {
365    DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
366    DisallowJavascriptExecution no_js(isolate);
367  
368    // Delegate to the underlying implementation.
369    DCHECK_EQ(state(), State::kReadyToFinalize);
370    ScopedTimer t(&time_taken_to_finalize_);
371    return UpdateState(FinalizeJobImpl(isolate), State::kSucceeded);
372  }
373  
RetryOptimization(BailoutReason reason)374  CompilationJob::Status OptimizedCompilationJob::RetryOptimization(
375      BailoutReason reason) {
376    DCHECK(compilation_info_->IsOptimizing());
377    compilation_info_->RetryOptimization(reason);
378    return UpdateState(FAILED, State::kFailed);
379  }
380  
AbortOptimization(BailoutReason reason)381  CompilationJob::Status OptimizedCompilationJob::AbortOptimization(
382      BailoutReason reason) {
383    DCHECK(compilation_info_->IsOptimizing());
384    compilation_info_->AbortOptimization(reason);
385    return UpdateState(FAILED, State::kFailed);
386  }
387  
RecordCompilationStats(CompilationMode mode,Isolate * isolate) const388  void OptimizedCompilationJob::RecordCompilationStats(CompilationMode mode,
389                                                       Isolate* isolate) const {
390    DCHECK(compilation_info()->IsOptimizing());
391    Handle<JSFunction> function = compilation_info()->closure();
392    double ms_creategraph = time_taken_to_prepare_.InMillisecondsF();
393    double ms_optimize = time_taken_to_execute_.InMillisecondsF();
394    double ms_codegen = time_taken_to_finalize_.InMillisecondsF();
395    CompilerTracer::TraceCompilationStats(
396        isolate, compilation_info(), ms_creategraph, ms_optimize, ms_codegen);
397    if (FLAG_trace_opt_stats) {
398      static double compilation_time = 0.0;
399      static int compiled_functions = 0;
400      static int code_size = 0;
401  
402      compilation_time += (ms_creategraph + ms_optimize + ms_codegen);
403      compiled_functions++;
404      code_size += function->shared().SourceSize();
405      PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
406             compiled_functions, code_size, compilation_time);
407    }
408    // Don't record samples from machines without high-resolution timers,
409    // as that can cause serious reporting issues. See the thread at
410    // http://g/chrome-metrics-team/NwwJEyL8odU/discussion for more details.
411    if (base::TimeTicks::IsHighResolution()) {
412      Counters* const counters = isolate->counters();
413      if (compilation_info()->is_osr()) {
414        counters->turbofan_osr_prepare()->AddSample(
415            static_cast<int>(time_taken_to_prepare_.InMicroseconds()));
416        counters->turbofan_osr_execute()->AddSample(
417            static_cast<int>(time_taken_to_execute_.InMicroseconds()));
418        counters->turbofan_osr_finalize()->AddSample(
419            static_cast<int>(time_taken_to_finalize_.InMicroseconds()));
420        counters->turbofan_osr_total_time()->AddSample(
421            static_cast<int>(ElapsedTime().InMicroseconds()));
422      } else {
423        counters->turbofan_optimize_prepare()->AddSample(
424            static_cast<int>(time_taken_to_prepare_.InMicroseconds()));
425        counters->turbofan_optimize_execute()->AddSample(
426            static_cast<int>(time_taken_to_execute_.InMicroseconds()));
427        counters->turbofan_optimize_finalize()->AddSample(
428            static_cast<int>(time_taken_to_finalize_.InMicroseconds()));
429        counters->turbofan_optimize_total_time()->AddSample(
430            static_cast<int>(ElapsedTime().InMicroseconds()));
431  
432        // Compute foreground / background time.
433        base::TimeDelta time_background;
434        base::TimeDelta time_foreground =
435            time_taken_to_prepare_ + time_taken_to_finalize_;
436        switch (mode) {
437          case OptimizedCompilationJob::kConcurrent:
438            time_background += time_taken_to_execute_;
439            counters->turbofan_optimize_concurrent_total_time()->AddSample(
440                static_cast<int>(ElapsedTime().InMicroseconds()));
441            break;
442          case OptimizedCompilationJob::kSynchronous:
443            counters->turbofan_optimize_non_concurrent_total_time()->AddSample(
444                static_cast<int>(ElapsedTime().InMicroseconds()));
445            time_foreground += time_taken_to_execute_;
446            break;
447        }
448        counters->turbofan_optimize_total_background()->AddSample(
449            static_cast<int>(time_background.InMicroseconds()));
450        counters->turbofan_optimize_total_foreground()->AddSample(
451            static_cast<int>(time_foreground.InMicroseconds()));
452      }
453      counters->turbofan_ticks()->AddSample(static_cast<int>(
454          compilation_info()->tick_counter().CurrentTicks() / 1000));
455    }
456  }
457  
RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,Isolate * isolate) const458  void OptimizedCompilationJob::RecordFunctionCompilation(
459      CodeEventListener::LogEventsAndTags tag, Isolate* isolate) const {
460    Handle<AbstractCode> abstract_code =
461        Handle<AbstractCode>::cast(compilation_info()->code());
462  
463    double time_taken_ms = time_taken_to_prepare_.InMillisecondsF() +
464                           time_taken_to_execute_.InMillisecondsF() +
465                           time_taken_to_finalize_.InMillisecondsF();
466  
467    Handle<Script> script(
468        Script::cast(compilation_info()->shared_info()->script()), isolate);
469    LogFunctionCompilation(tag, compilation_info()->shared_info(), script,
470                           abstract_code, true, time_taken_ms, isolate);
471  }
472  
473  // ----------------------------------------------------------------------------
474  // Local helper methods that make up the compilation pipeline.
475  
476  namespace {
477  
UseAsmWasm(FunctionLiteral * literal,bool asm_wasm_broken)478  bool UseAsmWasm(FunctionLiteral* literal, bool asm_wasm_broken) {
479    // Check whether asm.js validation is enabled.
480    if (!FLAG_validate_asm) return false;
481  
482    // Modules that have validated successfully, but were subsequently broken by
483    // invalid module instantiation attempts are off limit forever.
484    if (asm_wasm_broken) return false;
485  
486    // In stress mode we want to run the validator on everything.
487    if (FLAG_stress_validate_asm) return true;
488  
489    // In general, we respect the "use asm" directive.
490    return literal->scope()->IsAsmModule();
491  }
492  
InstallInterpreterTrampolineCopy(Isolate * isolate,Handle<SharedFunctionInfo> shared_info)493  void InstallInterpreterTrampolineCopy(Isolate* isolate,
494                                        Handle<SharedFunctionInfo> shared_info) {
495    DCHECK(FLAG_interpreted_frames_native_stack);
496    if (!shared_info->function_data(kAcquireLoad).IsBytecodeArray()) {
497      DCHECK(!shared_info->HasBytecodeArray());
498      return;
499    }
500    Handle<BytecodeArray> bytecode_array(shared_info->GetBytecodeArray(),
501                                         isolate);
502  
503    Handle<Code> code = isolate->factory()->CopyCode(Handle<Code>::cast(
504        isolate->factory()->interpreter_entry_trampoline_for_profiling()));
505  
506    Handle<InterpreterData> interpreter_data =
507        Handle<InterpreterData>::cast(isolate->factory()->NewStruct(
508            INTERPRETER_DATA_TYPE, AllocationType::kOld));
509  
510    interpreter_data->set_bytecode_array(*bytecode_array);
511    interpreter_data->set_interpreter_trampoline(*code);
512  
513    shared_info->set_interpreter_data(*interpreter_data);
514  
515    Handle<Script> script(Script::cast(shared_info->script()), isolate);
516    Handle<AbstractCode> abstract_code = Handle<AbstractCode>::cast(code);
517    int line_num =
518        Script::GetLineNumber(script, shared_info->StartPosition()) + 1;
519    int column_num =
520        Script::GetColumnNumber(script, shared_info->StartPosition()) + 1;
521    Handle<String> script_name =
522        handle(script->name().IsString() ? String::cast(script->name())
523                                         : ReadOnlyRoots(isolate).empty_string(),
524               isolate);
525    CodeEventListener::LogEventsAndTags log_tag = Logger::ToNativeByScript(
526        CodeEventListener::INTERPRETED_FUNCTION_TAG, *script);
527    PROFILE(isolate, CodeCreateEvent(log_tag, abstract_code, shared_info,
528                                     script_name, line_num, column_num));
529  }
530  
531  template <typename LocalIsolate>
InstallUnoptimizedCode(UnoptimizedCompilationInfo * compilation_info,Handle<SharedFunctionInfo> shared_info,LocalIsolate * isolate)532  void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
533                              Handle<SharedFunctionInfo> shared_info,
534                              LocalIsolate* isolate) {
535    if (compilation_info->has_bytecode_array()) {
536      DCHECK(!shared_info->HasBytecodeArray());  // Only compiled once.
537      DCHECK(!compilation_info->has_asm_wasm_data());
538      DCHECK(!shared_info->HasFeedbackMetadata());
539  
540      // If the function failed asm-wasm compilation, mark asm_wasm as broken
541      // to ensure we don't try to compile as asm-wasm.
542      if (compilation_info->literal()->scope()->IsAsmModule()) {
543        shared_info->set_is_asm_wasm_broken(true);
544      }
545  
546      shared_info->set_bytecode_array(*compilation_info->bytecode_array());
547  
548      Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(
549          isolate, compilation_info->feedback_vector_spec());
550      shared_info->set_feedback_metadata(*feedback_metadata);
551    } else {
552      DCHECK(compilation_info->has_asm_wasm_data());
553      // We should only have asm/wasm data when finalizing on the main thread.
554      DCHECK((std::is_same<LocalIsolate, Isolate>::value));
555      shared_info->set_asm_wasm_data(*compilation_info->asm_wasm_data());
556      shared_info->set_feedback_metadata(
557          ReadOnlyRoots(isolate).empty_feedback_metadata());
558    }
559  }
560  
LogUnoptimizedCompilation(Isolate * isolate,Handle<SharedFunctionInfo> shared_info,UnoptimizedCompileFlags flags,base::TimeDelta time_taken_to_execute,base::TimeDelta time_taken_to_finalize)561  void LogUnoptimizedCompilation(Isolate* isolate,
562                                 Handle<SharedFunctionInfo> shared_info,
563                                 UnoptimizedCompileFlags flags,
564                                 base::TimeDelta time_taken_to_execute,
565                                 base::TimeDelta time_taken_to_finalize) {
566    CodeEventListener::LogEventsAndTags log_tag;
567    if (flags.is_toplevel()) {
568      log_tag = flags.is_eval() ? CodeEventListener::EVAL_TAG
569                                : CodeEventListener::SCRIPT_TAG;
570    } else {
571      log_tag = flags.is_lazy_compile() ? CodeEventListener::LAZY_COMPILE_TAG
572                                        : CodeEventListener::FUNCTION_TAG;
573    }
574  
575    RecordUnoptimizedFunctionCompilation(isolate, log_tag, shared_info,
576                                         time_taken_to_execute,
577                                         time_taken_to_finalize);
578    RecordUnoptimizedCompilationStats(isolate, shared_info);
579  }
580  
581  template <typename LocalIsolate>
EnsureSharedFunctionInfosArrayOnScript(Handle<Script> script,ParseInfo * parse_info,LocalIsolate * isolate)582  void EnsureSharedFunctionInfosArrayOnScript(Handle<Script> script,
583                                              ParseInfo* parse_info,
584                                              LocalIsolate* isolate) {
585    DCHECK(parse_info->flags().is_toplevel());
586    if (script->shared_function_infos().length() > 0) {
587      DCHECK_EQ(script->shared_function_infos().length(),
588                parse_info->max_function_literal_id() + 1);
589      return;
590    }
591    Handle<WeakFixedArray> infos(isolate->factory()->NewWeakFixedArray(
592        parse_info->max_function_literal_id() + 1, AllocationType::kOld));
593    script->set_shared_function_infos(*infos);
594  }
595  
UpdateSharedFunctionFlagsAfterCompilation(FunctionLiteral * literal,SharedFunctionInfo shared_info)596  void UpdateSharedFunctionFlagsAfterCompilation(FunctionLiteral* literal,
597                                                 SharedFunctionInfo shared_info) {
598    DCHECK_EQ(shared_info.language_mode(), literal->language_mode());
599  
600    shared_info.set_has_duplicate_parameters(literal->has_duplicate_parameters());
601    shared_info.set_is_oneshot_iife(literal->is_oneshot_iife());
602    shared_info.UpdateAndFinalizeExpectedNofPropertiesFromEstimate(literal);
603    if (literal->dont_optimize_reason() != BailoutReason::kNoReason) {
604      shared_info.DisableOptimization(literal->dont_optimize_reason());
605    }
606  
607    shared_info.set_class_scope_has_private_brand(
608        literal->class_scope_has_private_brand());
609    shared_info.set_has_static_private_methods_or_accessors(
610        literal->has_static_private_methods_or_accessors());
611  
612    shared_info.SetScopeInfo(*literal->scope()->scope_info());
613  }
614  
615  // Finalize a single compilation job. This function can return
616  // RETRY_ON_MAIN_THREAD if the job cannot be finalized off-thread, in which case
617  // it should be safe to call it again on the main thread with the same job.
618  template <typename LocalIsolate>
FinalizeSingleUnoptimizedCompilationJob(UnoptimizedCompilationJob * job,Handle<SharedFunctionInfo> shared_info,LocalIsolate * isolate,FinalizeUnoptimizedCompilationDataList * finalize_unoptimized_compilation_data_list)619  CompilationJob::Status FinalizeSingleUnoptimizedCompilationJob(
620      UnoptimizedCompilationJob* job, Handle<SharedFunctionInfo> shared_info,
621      LocalIsolate* isolate,
622      FinalizeUnoptimizedCompilationDataList*
623          finalize_unoptimized_compilation_data_list) {
624    UnoptimizedCompilationInfo* compilation_info = job->compilation_info();
625  
626    CompilationJob::Status status = job->FinalizeJob(shared_info, isolate);
627    if (status == CompilationJob::SUCCEEDED) {
628      InstallUnoptimizedCode(compilation_info, shared_info, isolate);
629  
630      MaybeHandle<CoverageInfo> coverage_info;
631      if (compilation_info->has_coverage_info() &&
632          !shared_info->HasCoverageInfo()) {
633        coverage_info = compilation_info->coverage_info();
634      }
635  
636      finalize_unoptimized_compilation_data_list->emplace_back(
637          isolate, shared_info, coverage_info, job->time_taken_to_execute(),
638          job->time_taken_to_finalize());
639    }
640    DCHECK_IMPLIES(
641        status == CompilationJob::RETRY_ON_MAIN_THREAD,
642        (std::is_same<LocalIsolate, v8::internal::LocalIsolate>::value));
643    return status;
644  }
645  
646  std::unique_ptr<UnoptimizedCompilationJob>
ExecuteSingleUnoptimizedCompilationJob(ParseInfo * parse_info,FunctionLiteral * literal,AccountingAllocator * allocator,std::vector<FunctionLiteral * > * eager_inner_literals)647  ExecuteSingleUnoptimizedCompilationJob(
648      ParseInfo* parse_info, FunctionLiteral* literal,
649      AccountingAllocator* allocator,
650      std::vector<FunctionLiteral*>* eager_inner_literals) {
651    if (UseAsmWasm(literal, parse_info->flags().is_asm_wasm_broken())) {
652      std::unique_ptr<UnoptimizedCompilationJob> asm_job(
653          AsmJs::NewCompilationJob(parse_info, literal, allocator));
654      if (asm_job->ExecuteJob() == CompilationJob::SUCCEEDED) {
655        return asm_job;
656      }
657      // asm.js validation failed, fall through to standard unoptimized compile.
658      // Note: we rely on the fact that AsmJs jobs have done all validation in the
659      // PrepareJob and ExecuteJob phases and can't fail in FinalizeJob with
660      // with a validation error or another error that could be solve by falling
661      // through to standard unoptimized compile.
662    }
663    std::unique_ptr<UnoptimizedCompilationJob> job(
664        interpreter::Interpreter::NewCompilationJob(
665            parse_info, literal, allocator, eager_inner_literals));
666  
667    if (job->ExecuteJob() != CompilationJob::SUCCEEDED) {
668      // Compilation failed, return null.
669      return std::unique_ptr<UnoptimizedCompilationJob>();
670    }
671  
672    return job;
673  }
674  
RecursivelyExecuteUnoptimizedCompilationJobs(ParseInfo * parse_info,FunctionLiteral * literal,AccountingAllocator * allocator,UnoptimizedCompilationJobList * function_jobs)675  bool RecursivelyExecuteUnoptimizedCompilationJobs(
676      ParseInfo* parse_info, FunctionLiteral* literal,
677      AccountingAllocator* allocator,
678      UnoptimizedCompilationJobList* function_jobs) {
679    std::vector<FunctionLiteral*> eager_inner_literals;
680    std::unique_ptr<UnoptimizedCompilationJob> job =
681        ExecuteSingleUnoptimizedCompilationJob(parse_info, literal, allocator,
682                                               &eager_inner_literals);
683  
684    if (!job) return false;
685  
686    // Recursively compile eager inner literals.
687    for (FunctionLiteral* inner_literal : eager_inner_literals) {
688      if (!RecursivelyExecuteUnoptimizedCompilationJobs(
689              parse_info, inner_literal, allocator, function_jobs)) {
690        return false;
691      }
692    }
693  
694    function_jobs->emplace_front(std::move(job));
695    return true;
696  }
697  
698  template <typename LocalIsolate>
IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(LocalIsolate * isolate,Handle<SharedFunctionInfo> outer_shared_info,Handle<Script> script,ParseInfo * parse_info,AccountingAllocator * allocator,IsCompiledScope * is_compiled_scope,FinalizeUnoptimizedCompilationDataList * finalize_unoptimized_compilation_data_list,DeferredFinalizationJobDataList * jobs_to_retry_finalization_on_main_thread)699  bool IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
700      LocalIsolate* isolate, Handle<SharedFunctionInfo> outer_shared_info,
701      Handle<Script> script, ParseInfo* parse_info,
702      AccountingAllocator* allocator, IsCompiledScope* is_compiled_scope,
703      FinalizeUnoptimizedCompilationDataList*
704          finalize_unoptimized_compilation_data_list,
705      DeferredFinalizationJobDataList*
706          jobs_to_retry_finalization_on_main_thread) {
707    DeclarationScope::AllocateScopeInfos(parse_info, isolate);
708  
709    std::vector<FunctionLiteral*> functions_to_compile;
710    functions_to_compile.push_back(parse_info->literal());
711  
712    while (!functions_to_compile.empty()) {
713      FunctionLiteral* literal = functions_to_compile.back();
714      functions_to_compile.pop_back();
715      Handle<SharedFunctionInfo> shared_info =
716          Compiler::GetSharedFunctionInfo(literal, script, isolate);
717      if (shared_info->is_compiled()) continue;
718  
719      std::unique_ptr<UnoptimizedCompilationJob> job =
720          ExecuteSingleUnoptimizedCompilationJob(parse_info, literal, allocator,
721                                                 &functions_to_compile);
722      if (!job) return false;
723  
724      UpdateSharedFunctionFlagsAfterCompilation(literal, *shared_info);
725  
726      auto finalization_status = FinalizeSingleUnoptimizedCompilationJob(
727          job.get(), shared_info, isolate,
728          finalize_unoptimized_compilation_data_list);
729  
730      switch (finalization_status) {
731        case CompilationJob::SUCCEEDED:
732          if (shared_info.is_identical_to(outer_shared_info)) {
733            // Ensure that the top level function is retained.
734            *is_compiled_scope = shared_info->is_compiled_scope(isolate);
735            DCHECK(is_compiled_scope->is_compiled());
736          }
737          break;
738  
739        case CompilationJob::FAILED:
740          return false;
741  
742        case CompilationJob::RETRY_ON_MAIN_THREAD:
743          // This should not happen on the main thread.
744          DCHECK((!std::is_same<LocalIsolate, Isolate>::value));
745          DCHECK_NOT_NULL(jobs_to_retry_finalization_on_main_thread);
746  
747          // Clear the literal and ParseInfo to prevent further attempts to access
748          // them.
749          job->compilation_info()->ClearLiteral();
750          job->ClearParseInfo();
751          jobs_to_retry_finalization_on_main_thread->emplace_back(
752              isolate, shared_info, std::move(job));
753          break;
754      }
755    }
756  
757    // Report any warnings generated during compilation.
758    if (parse_info->pending_error_handler()->has_pending_warnings()) {
759      parse_info->pending_error_handler()->PrepareWarnings(isolate);
760    }
761  
762    return true;
763  }
764  
FinalizeAllUnoptimizedCompilationJobs(ParseInfo * parse_info,Isolate * isolate,Handle<Script> script,UnoptimizedCompilationJobList * compilation_jobs,FinalizeUnoptimizedCompilationDataList * finalize_unoptimized_compilation_data_list)765  bool FinalizeAllUnoptimizedCompilationJobs(
766      ParseInfo* parse_info, Isolate* isolate, Handle<Script> script,
767      UnoptimizedCompilationJobList* compilation_jobs,
768      FinalizeUnoptimizedCompilationDataList*
769          finalize_unoptimized_compilation_data_list) {
770    DCHECK(AllowCompilation::IsAllowed(isolate));
771    DCHECK(!compilation_jobs->empty());
772  
773    // TODO(rmcilroy): Clear native context in debug once AsmJS generates doesn't
774    // rely on accessing native context during finalization.
775  
776    // Allocate scope infos for the literal.
777    DeclarationScope::AllocateScopeInfos(parse_info, isolate);
778  
779    // Finalize the functions' compilation jobs.
780    for (auto&& job : *compilation_jobs) {
781      FunctionLiteral* literal = job->compilation_info()->literal();
782      Handle<SharedFunctionInfo> shared_info =
783          Compiler::GetSharedFunctionInfo(literal, script, isolate);
784      // The inner function might be compiled already if compiling for debug.
785      if (shared_info->is_compiled()) continue;
786      UpdateSharedFunctionFlagsAfterCompilation(literal, *shared_info);
787      if (FinalizeSingleUnoptimizedCompilationJob(
788              job.get(), shared_info, isolate,
789              finalize_unoptimized_compilation_data_list) !=
790          CompilationJob::SUCCEEDED) {
791        return false;
792      }
793    }
794  
795    // Report any warnings generated during compilation.
796    if (parse_info->pending_error_handler()->has_pending_warnings()) {
797      parse_info->pending_error_handler()->PrepareWarnings(isolate);
798    }
799  
800    return true;
801  }
802  
FinalizeDeferredUnoptimizedCompilationJobs(Isolate * isolate,Handle<Script> script,DeferredFinalizationJobDataList * deferred_jobs,PendingCompilationErrorHandler * pending_error_handler,FinalizeUnoptimizedCompilationDataList * finalize_unoptimized_compilation_data_list)803  bool FinalizeDeferredUnoptimizedCompilationJobs(
804      Isolate* isolate, Handle<Script> script,
805      DeferredFinalizationJobDataList* deferred_jobs,
806      PendingCompilationErrorHandler* pending_error_handler,
807      FinalizeUnoptimizedCompilationDataList*
808          finalize_unoptimized_compilation_data_list) {
809    DCHECK(AllowCompilation::IsAllowed(isolate));
810  
811    if (deferred_jobs->empty()) return true;
812  
813    // TODO(rmcilroy): Clear native context in debug once AsmJS generates doesn't
814    // rely on accessing native context during finalization.
815  
816    // Finalize the deferred compilation jobs.
817    for (auto&& job : *deferred_jobs) {
818      Handle<SharedFunctionInfo> shared_info = job.function_handle();
819      if (FinalizeSingleUnoptimizedCompilationJob(
820              job.job(), shared_info, isolate,
821              finalize_unoptimized_compilation_data_list) !=
822          CompilationJob::SUCCEEDED) {
823        return false;
824      }
825    }
826  
827    // Report any warnings generated during deferred finalization.
828    if (pending_error_handler->has_pending_warnings()) {
829      pending_error_handler->PrepareWarnings(isolate);
830    }
831  
832    return true;
833  }
834  
GetCodeFromOptimizedCodeCache(Handle<JSFunction> function,BailoutId osr_offset,CodeKind code_kind)835  V8_WARN_UNUSED_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeCache(
836      Handle<JSFunction> function, BailoutId osr_offset, CodeKind code_kind) {
837    RuntimeCallTimerScope runtimeTimer(
838        function->GetIsolate(),
839        RuntimeCallCounterId::kCompileGetFromOptimizedCodeMap);
840    Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate());
841    Isolate* isolate = function->GetIsolate();
842    DisallowHeapAllocation no_gc;
843    Code code;
844    if (osr_offset.IsNone() && function->has_feedback_vector()) {
845      FeedbackVector feedback_vector = function->feedback_vector();
846      feedback_vector.EvictOptimizedCodeMarkedForDeoptimization(
847          function->shared(), "GetCodeFromOptimizedCodeCache");
848      code = feedback_vector.optimized_code();
849    } else if (!osr_offset.IsNone()) {
850      code = function->context()
851                 .native_context()
852                 .GetOSROptimizedCodeCache()
853                 .GetOptimizedCode(shared, osr_offset, isolate);
854    }
855    DCHECK_IMPLIES(!code.is_null(), code.kind() <= code_kind);
856    if (!code.is_null() && code.kind() == code_kind) {
857      // Caching of optimized code enabled and optimized code found.
858      DCHECK(!code.marked_for_deoptimization());
859      DCHECK(function->shared().is_compiled());
860      DCHECK(CodeKindIsStoredInOptimizedCodeCache(code.kind()));
861      DCHECK_IMPLIES(!osr_offset.IsNone(), CodeKindCanOSR(code.kind()));
862      return Handle<Code>(code, isolate);
863    }
864    return MaybeHandle<Code>();
865  }
866  
ClearOptimizedCodeCache(OptimizedCompilationInfo * compilation_info)867  void ClearOptimizedCodeCache(OptimizedCompilationInfo* compilation_info) {
868    DCHECK(UsesOptimizationMarker(compilation_info->code_kind()));
869    Handle<JSFunction> function = compilation_info->closure();
870    if (compilation_info->osr_offset().IsNone()) {
871      Handle<FeedbackVector> vector =
872          handle(function->feedback_vector(), function->GetIsolate());
873      vector->ClearOptimizationMarker();
874    }
875  }
876  
InsertCodeIntoOptimizedCodeCache(OptimizedCompilationInfo * compilation_info)877  void InsertCodeIntoOptimizedCodeCache(
878      OptimizedCompilationInfo* compilation_info) {
879    const CodeKind kind = compilation_info->code_kind();
880    if (!CodeKindIsStoredInOptimizedCodeCache(kind)) {
881      if (UsesOptimizationMarker(kind)) {
882        ClearOptimizedCodeCache(compilation_info);
883      }
884      return;
885    }
886  
887    if (compilation_info->function_context_specializing()) {
888      // Function context specialization folds-in the function context, so no
889      // sharing can occur. Make sure the optimized code cache is cleared.
890      ClearOptimizedCodeCache(compilation_info);
891      return;
892    }
893  
894    // Cache optimized code.
895    Handle<Code> code = compilation_info->code();
896    Handle<JSFunction> function = compilation_info->closure();
897    Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate());
898    Handle<NativeContext> native_context(function->context().native_context(),
899                                         function->GetIsolate());
900    if (compilation_info->osr_offset().IsNone()) {
901      Handle<FeedbackVector> vector =
902          handle(function->feedback_vector(), function->GetIsolate());
903      FeedbackVector::SetOptimizedCode(vector, code);
904    } else {
905      DCHECK(CodeKindCanOSR(kind));
906      OSROptimizedCodeCache::AddOptimizedCode(native_context, shared, code,
907                                              compilation_info->osr_offset());
908    }
909  }
910  
InsertCodeIntoCompilationCache(Isolate * isolate,OptimizedCompilationInfo * info)911  void InsertCodeIntoCompilationCache(Isolate* isolate,
912                                      OptimizedCompilationInfo* info) {
913    if (!CodeKindIsNativeContextIndependentJSFunction(info->code_kind())) return;
914  
915    DCHECK(info->osr_offset().IsNone());
916  
917    Handle<Code> code = info->code();
918    DCHECK(!info->function_context_specializing());
919  
920    Handle<SharedFunctionInfo> sfi = info->shared_info();
921    CompilationCache* cache = isolate->compilation_cache();
922    cache->PutCode(sfi, code);
923    DCHECK(!cache->LookupCode(sfi).is_null());
924  
925    sfi->set_may_have_cached_code(true);
926  
927    if (FLAG_trace_turbo_nci) CompilationCacheCode::TraceInsertion(sfi, code);
928  }
929  
GetCodeFromCompilationCache(Isolate * isolate,Handle<SharedFunctionInfo> shared)930  V8_WARN_UNUSED_RESULT MaybeHandle<Code> GetCodeFromCompilationCache(
931      Isolate* isolate, Handle<SharedFunctionInfo> shared) {
932    if (!shared->may_have_cached_code()) return {};
933    return shared->TryGetCachedCode(isolate);
934  }
935  
936  // Runs PrepareJob in the proper compilation & canonical scopes. Handles will be
937  // allocated in a persistent handle scope that is detached and handed off to the
938  // {compilation_info} after PrepareJob.
PrepareJobWithHandleScope(OptimizedCompilationJob * job,Isolate * isolate,OptimizedCompilationInfo * compilation_info)939  bool PrepareJobWithHandleScope(OptimizedCompilationJob* job, Isolate* isolate,
940                                 OptimizedCompilationInfo* compilation_info) {
941    CompilationHandleScope compilation(isolate, compilation_info);
942    CanonicalHandleScope canonical(isolate, compilation_info);
943    compilation_info->ReopenHandlesInNewHandleScope(isolate);
944    return job->PrepareJob(isolate) == CompilationJob::SUCCEEDED;
945  }
946  
GetOptimizedCodeNow(OptimizedCompilationJob * job,Isolate * isolate,OptimizedCompilationInfo * compilation_info)947  bool GetOptimizedCodeNow(OptimizedCompilationJob* job, Isolate* isolate,
948                           OptimizedCompilationInfo* compilation_info) {
949    TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
950    RuntimeCallTimerScope runtimeTimer(
951        isolate, RuntimeCallCounterId::kOptimizeNonConcurrent);
952    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
953                 "V8.OptimizeNonConcurrent");
954  
955    if (!PrepareJobWithHandleScope(job, isolate, compilation_info)) {
956      CompilerTracer::TraceAbortedJob(isolate, compilation_info);
957      return false;
958    }
959  
960    {
961      LocalIsolate local_isolate(isolate, ThreadKind::kMain);
962      if (job->ExecuteJob(isolate->counters()->runtime_call_stats(),
963                          &local_isolate)) {
964        CompilerTracer::TraceAbortedJob(isolate, compilation_info);
965        return false;
966      }
967    }
968  
969    if (job->FinalizeJob(isolate) != CompilationJob::SUCCEEDED) {
970      CompilerTracer::TraceAbortedJob(isolate, compilation_info);
971      return false;
972    }
973  
974    // Success!
975    job->RecordCompilationStats(OptimizedCompilationJob::kSynchronous, isolate);
976    DCHECK(!isolate->has_pending_exception());
977    InsertCodeIntoOptimizedCodeCache(compilation_info);
978    job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, isolate);
979    return true;
980  }
981  
GetOptimizedCodeLater(std::unique_ptr<OptimizedCompilationJob> job,Isolate * isolate,OptimizedCompilationInfo * compilation_info,CodeKind code_kind,Handle<JSFunction> function)982  bool GetOptimizedCodeLater(std::unique_ptr<OptimizedCompilationJob> job,
983                             Isolate* isolate,
984                             OptimizedCompilationInfo* compilation_info,
985                             CodeKind code_kind, Handle<JSFunction> function) {
986    if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) {
987      if (FLAG_trace_concurrent_recompilation) {
988        PrintF("  ** Compilation queue full, will retry optimizing ");
989        compilation_info->closure()->ShortPrint();
990        PrintF(" later.\n");
991      }
992      return false;
993    }
994  
995    if (isolate->heap()->HighMemoryPressure()) {
996      if (FLAG_trace_concurrent_recompilation) {
997        PrintF("  ** High memory pressure, will retry optimizing ");
998        compilation_info->closure()->ShortPrint();
999        PrintF(" later.\n");
1000      }
1001      return false;
1002    }
1003  
1004    TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
1005    RuntimeCallTimerScope runtimeTimer(
1006        isolate, RuntimeCallCounterId::kOptimizeConcurrentPrepare);
1007    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1008                 "V8.OptimizeConcurrentPrepare");
1009  
1010    if (!PrepareJobWithHandleScope(job.get(), isolate, compilation_info)) {
1011      return false;
1012    }
1013  
1014    // The background recompile will own this job.
1015    isolate->optimizing_compile_dispatcher()->QueueForOptimization(job.get());
1016    job.release();
1017  
1018    if (FLAG_trace_concurrent_recompilation) {
1019      PrintF("  ** Queued ");
1020      compilation_info->closure()->ShortPrint();
1021      PrintF(" for concurrent optimization.\n");
1022    }
1023  
1024    if (CodeKindIsStoredInOptimizedCodeCache(code_kind)) {
1025      function->SetOptimizationMarker(OptimizationMarker::kInOptimizationQueue);
1026    }
1027  
1028    // Note: Usually the active tier is expected to be Ignition or NCI at this
1029    // point (in other words we don't expect to optimize if the function is
1030    // already TF-optimized). There is a special case for OSR though, for which
1031    // we *can* reach this point even if we've already generated non-OSR'd TF
1032    // code.
1033    DCHECK(function->shared().HasBytecodeArray());
1034    return true;
1035  }
1036  
1037  // Returns the code object at which execution continues after a concurrent
1038  // optimization job has been started (but not finished).
ContinuationForConcurrentOptimization(Isolate * isolate,Handle<JSFunction> function)1039  Handle<Code> ContinuationForConcurrentOptimization(
1040      Isolate* isolate, Handle<JSFunction> function) {
1041    Handle<Code> cached_code;
1042    if (FLAG_turbo_nci && function->NextTier() == CodeKindForTopTier() &&
1043        GetCodeFromCompilationCache(isolate, handle(function->shared(), isolate))
1044            .ToHandle(&cached_code)) {
1045      // Tiering up to Turbofan and cached optimized code exists. Continue
1046      // execution there until TF optimization has finished.
1047      return cached_code;
1048    } else if (FLAG_turboprop_as_midtier &&
1049               function->HasAvailableOptimizedCode()) {
1050      DCHECK(function->NextTier() == CodeKind::TURBOFAN);
1051      // It is possible that we have marked a closure for TurboFan optimization
1052      // but the marker is processed by another closure that doesn't have
1053      // optimized code yet. So heal the closure here and return the optimized
1054      // code.
1055      if (!function->HasAttachedOptimizedCode()) {
1056        DCHECK(function->feedback_vector().has_optimized_code());
1057        function->set_code(function->feedback_vector().optimized_code());
1058      }
1059      return handle(function->code(), isolate);
1060    }
1061    return BUILTIN_CODE(isolate, InterpreterEntryTrampoline);
1062  }
1063  
GetOptimizedCode(Handle<JSFunction> function,ConcurrencyMode mode,CodeKind code_kind,BailoutId osr_offset=BailoutId::None (),JavaScriptFrame * osr_frame=nullptr)1064  MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
1065                                     ConcurrencyMode mode, CodeKind code_kind,
1066                                     BailoutId osr_offset = BailoutId::None(),
1067                                     JavaScriptFrame* osr_frame = nullptr) {
1068    DCHECK(CodeKindIsOptimizedJSFunction(code_kind));
1069  
1070    Isolate* isolate = function->GetIsolate();
1071    Handle<SharedFunctionInfo> shared(function->shared(), isolate);
1072  
1073    // Make sure we clear the optimization marker on the function so that we
1074    // don't try to re-optimize.
1075    // If compiling for NCI caching only (which does not use the optimization
1076    // marker), don't touch the marker to avoid interfering with Turbofan
1077    // compilation.
1078    if (UsesOptimizationMarker(code_kind) && function->HasOptimizationMarker()) {
1079      function->ClearOptimizationMarker();
1080    }
1081  
1082    if (shared->optimization_disabled() &&
1083        shared->disable_optimization_reason() == BailoutReason::kNeverOptimize) {
1084      return {};
1085    }
1086  
1087    // Do not optimize when debugger needs to hook into every call.
1088    if (isolate->debug()->needs_check_on_function_call()) return {};
1089  
1090    // Do not use TurboFan if we need to be able to set break points.
1091    if (shared->HasBreakInfo()) return {};
1092  
1093    // Do not use TurboFan if optimization is disabled or function doesn't pass
1094    // turbo_filter.
1095    if (!FLAG_opt || !shared->PassesFilter(FLAG_turbo_filter)) return {};
1096  
1097    // If code was pending optimization for testing, remove the entry from the
1098    // table that was preventing the bytecode from being flushed.
1099    if (V8_UNLIKELY(FLAG_testing_d8_test_runner)) {
1100      PendingOptimizationTable::FunctionWasOptimized(isolate, function);
1101    }
1102  
1103    // Check the optimized code cache (stored on the SharedFunctionInfo).
1104    if (CodeKindIsStoredInOptimizedCodeCache(code_kind)) {
1105      Handle<Code> cached_code;
1106      if (GetCodeFromOptimizedCodeCache(function, osr_offset, code_kind)
1107              .ToHandle(&cached_code)) {
1108        CompilerTracer::TraceOptimizedCodeCacheHit(isolate, function, osr_offset,
1109                                                   code_kind);
1110        return cached_code;
1111      }
1112    }
1113  
1114    // Reset profiler ticks, function is no longer considered hot.
1115    DCHECK(shared->is_compiled());
1116    function->feedback_vector().set_profiler_ticks(0);
1117  
1118    // Check the compilation cache (stored on the Isolate, shared between native
1119    // contexts).
1120    if (CodeKindIsNativeContextIndependentJSFunction(code_kind)) {
1121      DCHECK(osr_offset.IsNone());
1122      DCHECK(FLAG_turbo_nci_as_midtier || !FLAG_turbo_nci_delayed_codegen ||
1123             shared->has_optimized_at_least_once());
1124  
1125      Handle<Code> cached_code;
1126      if (GetCodeFromCompilationCache(isolate, shared).ToHandle(&cached_code)) {
1127        CHECK_EQ(cached_code->kind(), CodeKind::NATIVE_CONTEXT_INDEPENDENT);
1128        if (FLAG_trace_turbo_nci) {
1129          CompilationCacheCode::TraceHit(shared, cached_code);
1130        }
1131        return cached_code;
1132      }
1133    }
1134  
1135    VMState<COMPILER> state(isolate);
1136    TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate);
1137    RuntimeCallTimerScope runtimeTimer(isolate,
1138                                       RuntimeCallCounterId::kOptimizeCode);
1139    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.OptimizeCode");
1140  
1141    DCHECK(!isolate->has_pending_exception());
1142    PostponeInterruptsScope postpone(isolate);
1143    bool has_script = shared->script().IsScript();
1144    // BUG(5946): This DCHECK is necessary to make certain that we won't
1145    // tolerate the lack of a script without bytecode.
1146    DCHECK_IMPLIES(!has_script, shared->HasBytecodeArray());
1147    std::unique_ptr<OptimizedCompilationJob> job(
1148        compiler::Pipeline::NewCompilationJob(isolate, function, code_kind,
1149                                              has_script, osr_offset, osr_frame));
1150    OptimizedCompilationInfo* compilation_info = job->compilation_info();
1151  
1152    // Prepare the job and launch concurrent compilation, or compile now.
1153    if (mode == ConcurrencyMode::kConcurrent) {
1154      if (GetOptimizedCodeLater(std::move(job), isolate, compilation_info,
1155                                code_kind, function)) {
1156        return ContinuationForConcurrentOptimization(isolate, function);
1157      }
1158    } else {
1159      DCHECK_EQ(mode, ConcurrencyMode::kNotConcurrent);
1160      if (GetOptimizedCodeNow(job.get(), isolate, compilation_info)) {
1161        InsertCodeIntoCompilationCache(isolate, compilation_info);
1162        return compilation_info->code();
1163      }
1164    }
1165  
1166    if (isolate->has_pending_exception()) isolate->clear_pending_exception();
1167    return {};
1168  }
1169  
FailAndClearPendingException(Isolate * isolate)1170  bool FailAndClearPendingException(Isolate* isolate) {
1171    isolate->clear_pending_exception();
1172    return false;
1173  }
1174  
1175  template <typename LocalIsolate>
PreparePendingException(LocalIsolate * isolate,ParseInfo * parse_info)1176  bool PreparePendingException(LocalIsolate* isolate, ParseInfo* parse_info) {
1177    if (parse_info->pending_error_handler()->has_pending_error()) {
1178      parse_info->pending_error_handler()->PrepareErrors(
1179          isolate, parse_info->ast_value_factory());
1180    }
1181    return false;
1182  }
1183  
FailWithPreparedPendingException(Isolate * isolate,Handle<Script> script,const PendingCompilationErrorHandler * pending_error_handler)1184  bool FailWithPreparedPendingException(
1185      Isolate* isolate, Handle<Script> script,
1186      const PendingCompilationErrorHandler* pending_error_handler) {
1187    if (!isolate->has_pending_exception()) {
1188      if (pending_error_handler->has_pending_error()) {
1189        pending_error_handler->ReportErrors(isolate, script);
1190      } else {
1191        isolate->StackOverflow();
1192      }
1193    }
1194    return false;
1195  }
1196  
FailWithPendingException(Isolate * isolate,Handle<Script> script,ParseInfo * parse_info,Compiler::ClearExceptionFlag flag)1197  bool FailWithPendingException(Isolate* isolate, Handle<Script> script,
1198                                ParseInfo* parse_info,
1199                                Compiler::ClearExceptionFlag flag) {
1200    if (flag == Compiler::CLEAR_EXCEPTION) {
1201      return FailAndClearPendingException(isolate);
1202    }
1203  
1204    PreparePendingException(isolate, parse_info);
1205    return FailWithPreparedPendingException(isolate, script,
1206                                            parse_info->pending_error_handler());
1207  }
1208  
FinalizeUnoptimizedCompilation(Isolate * isolate,Handle<Script> script,const UnoptimizedCompileFlags & flags,const UnoptimizedCompileState * compile_state,const FinalizeUnoptimizedCompilationDataList & finalize_unoptimized_compilation_data_list)1209  void FinalizeUnoptimizedCompilation(
1210      Isolate* isolate, Handle<Script> script,
1211      const UnoptimizedCompileFlags& flags,
1212      const UnoptimizedCompileState* compile_state,
1213      const FinalizeUnoptimizedCompilationDataList&
1214          finalize_unoptimized_compilation_data_list) {
1215    if (compile_state->pending_error_handler()->has_pending_warnings()) {
1216      compile_state->pending_error_handler()->ReportWarnings(isolate, script);
1217    }
1218  
1219    bool need_source_positions = FLAG_stress_lazy_source_positions ||
1220                                 (!flags.collect_source_positions() &&
1221                                  isolate->NeedsSourcePositionsForProfiling());
1222  
1223    for (const auto& finalize_data : finalize_unoptimized_compilation_data_list) {
1224      Handle<SharedFunctionInfo> shared_info = finalize_data.function_handle();
1225      // It's unlikely, but possible, that the bytecode was flushed between being
1226      // allocated and now, so guard against that case, and against it being
1227      // flushed in the middle of this loop.
1228      IsCompiledScope is_compiled_scope(*shared_info, isolate);
1229      if (!is_compiled_scope.is_compiled()) continue;
1230  
1231      if (need_source_positions) {
1232        SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
1233      }
1234      if (FLAG_interpreted_frames_native_stack) {
1235        InstallInterpreterTrampolineCopy(isolate, shared_info);
1236      }
1237      Handle<CoverageInfo> coverage_info;
1238      if (finalize_data.coverage_info().ToHandle(&coverage_info)) {
1239        isolate->debug()->InstallCoverageInfo(shared_info, coverage_info);
1240      }
1241  
1242      LogUnoptimizedCompilation(isolate, shared_info, flags,
1243                                finalize_data.time_taken_to_execute(),
1244                                finalize_data.time_taken_to_finalize());
1245    }
1246  }
1247  
FinalizeUnoptimizedScriptCompilation(Isolate * isolate,Handle<Script> script,const UnoptimizedCompileFlags & flags,const UnoptimizedCompileState * compile_state,const FinalizeUnoptimizedCompilationDataList & finalize_unoptimized_compilation_data_list)1248  void FinalizeUnoptimizedScriptCompilation(
1249      Isolate* isolate, Handle<Script> script,
1250      const UnoptimizedCompileFlags& flags,
1251      const UnoptimizedCompileState* compile_state,
1252      const FinalizeUnoptimizedCompilationDataList&
1253          finalize_unoptimized_compilation_data_list) {
1254    FinalizeUnoptimizedCompilation(isolate, script, flags, compile_state,
1255                                   finalize_unoptimized_compilation_data_list);
1256  
1257    script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
1258  
1259    UnoptimizedCompileState::ParallelTasks* parallel_tasks =
1260        compile_state->parallel_tasks();
1261    if (parallel_tasks) {
1262      CompilerDispatcher* dispatcher = parallel_tasks->dispatcher();
1263      for (auto& it : *parallel_tasks) {
1264        FunctionLiteral* literal = it.first;
1265        CompilerDispatcher::JobId job_id = it.second;
1266        MaybeHandle<SharedFunctionInfo> maybe_shared_for_task =
1267            script->FindSharedFunctionInfo(isolate,
1268                                           literal->function_literal_id());
1269        Handle<SharedFunctionInfo> shared_for_task;
1270        if (maybe_shared_for_task.ToHandle(&shared_for_task)) {
1271          dispatcher->RegisterSharedFunctionInfo(job_id, *shared_for_task);
1272        } else {
1273          dispatcher->AbortJob(job_id);
1274        }
1275      }
1276    }
1277  
1278    if (isolate->NeedsSourcePositionsForProfiling()) {
1279      Script::InitLineEnds(isolate, script);
1280    }
1281  }
1282  
1283  // Create shared function info for top level and shared function infos array for
1284  // inner functions.
1285  template <typename LocalIsolate>
CreateTopLevelSharedFunctionInfo(ParseInfo * parse_info,Handle<Script> script,LocalIsolate * isolate)1286  Handle<SharedFunctionInfo> CreateTopLevelSharedFunctionInfo(
1287      ParseInfo* parse_info, Handle<Script> script, LocalIsolate* isolate) {
1288    EnsureSharedFunctionInfosArrayOnScript(script, parse_info, isolate);
1289    DCHECK_EQ(kNoSourcePosition,
1290              parse_info->literal()->function_token_position());
1291    return isolate->factory()->NewSharedFunctionInfoForLiteral(
1292        parse_info->literal(), script, true);
1293  }
1294  
CompileToplevel(ParseInfo * parse_info,Handle<Script> script,MaybeHandle<ScopeInfo> maybe_outer_scope_info,Isolate * isolate,IsCompiledScope * is_compiled_scope)1295  MaybeHandle<SharedFunctionInfo> CompileToplevel(
1296      ParseInfo* parse_info, Handle<Script> script,
1297      MaybeHandle<ScopeInfo> maybe_outer_scope_info, Isolate* isolate,
1298      IsCompiledScope* is_compiled_scope) {
1299    TimerEventScope<TimerEventCompileCode> top_level_timer(isolate);
1300    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
1301    DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
1302  
1303    PostponeInterruptsScope postpone(isolate);
1304    DCHECK(!isolate->native_context().is_null());
1305    RuntimeCallTimerScope runtimeTimer(
1306        isolate, parse_info->flags().is_eval()
1307                     ? RuntimeCallCounterId::kCompileEval
1308                     : RuntimeCallCounterId::kCompileScript);
1309    VMState<BYTECODE_COMPILER> state(isolate);
1310    if (parse_info->literal() == nullptr &&
1311        !parsing::ParseProgram(parse_info, script, maybe_outer_scope_info,
1312                               isolate, parsing::ReportStatisticsMode::kYes)) {
1313      FailWithPendingException(isolate, script, parse_info,
1314                               Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
1315      return MaybeHandle<SharedFunctionInfo>();
1316    }
1317    // Measure how long it takes to do the compilation; only take the
1318    // rest of the function into account to avoid overlap with the
1319    // parsing statistics.
1320    HistogramTimer* rate = parse_info->flags().is_eval()
1321                               ? isolate->counters()->compile_eval()
1322                               : isolate->counters()->compile();
1323    HistogramTimerScope timer(rate);
1324    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1325                 parse_info->flags().is_eval() ? "V8.CompileEval" : "V8.Compile");
1326  
1327    // Prepare and execute compilation of the outer-most function.
1328  
1329    // Create the SharedFunctionInfo and add it to the script's list.
1330    Handle<SharedFunctionInfo> shared_info =
1331        CreateTopLevelSharedFunctionInfo(parse_info, script, isolate);
1332  
1333    FinalizeUnoptimizedCompilationDataList
1334        finalize_unoptimized_compilation_data_list;
1335  
1336    if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
1337            isolate, shared_info, script, parse_info, isolate->allocator(),
1338            is_compiled_scope, &finalize_unoptimized_compilation_data_list,
1339            nullptr)) {
1340      FailWithPendingException(isolate, script, parse_info,
1341                               Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
1342      return MaybeHandle<SharedFunctionInfo>();
1343    }
1344  
1345    // Character stream shouldn't be used again.
1346    parse_info->ResetCharacterStream();
1347  
1348    FinalizeUnoptimizedScriptCompilation(
1349        isolate, script, parse_info->flags(), parse_info->state(),
1350        finalize_unoptimized_compilation_data_list);
1351    return shared_info;
1352  }
1353  
RuntimeCallCounterIdForCompileBackground(ParseInfo * parse_info)1354  RuntimeCallCounterId RuntimeCallCounterIdForCompileBackground(
1355      ParseInfo* parse_info) {
1356    if (parse_info->flags().is_toplevel()) {
1357      if (parse_info->flags().is_eval()) {
1358        return RuntimeCallCounterId::kCompileBackgroundEval;
1359      }
1360      return RuntimeCallCounterId::kCompileBackgroundScript;
1361    }
1362    return RuntimeCallCounterId::kCompileBackgroundFunction;
1363  }
1364  
CompileAndFinalizeOnBackgroundThread(ParseInfo * parse_info,AccountingAllocator * allocator,Handle<Script> script,LocalIsolate * isolate,FinalizeUnoptimizedCompilationDataList * finalize_unoptimized_compilation_data_list,DeferredFinalizationJobDataList * jobs_to_retry_finalization_on_main_thread,IsCompiledScope * is_compiled_scope)1365  MaybeHandle<SharedFunctionInfo> CompileAndFinalizeOnBackgroundThread(
1366      ParseInfo* parse_info, AccountingAllocator* allocator,
1367      Handle<Script> script, LocalIsolate* isolate,
1368      FinalizeUnoptimizedCompilationDataList*
1369          finalize_unoptimized_compilation_data_list,
1370      DeferredFinalizationJobDataList* jobs_to_retry_finalization_on_main_thread,
1371      IsCompiledScope* is_compiled_scope) {
1372    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1373                 "V8.CompileCodeBackground");
1374    RuntimeCallTimerScope runtimeTimer(
1375        parse_info->runtime_call_stats(),
1376        RuntimeCallCounterIdForCompileBackground(parse_info));
1377  
1378    Handle<SharedFunctionInfo> shared_info =
1379        CreateTopLevelSharedFunctionInfo(parse_info, script, isolate);
1380  
1381    if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
1382            isolate, shared_info, script, parse_info, allocator,
1383            is_compiled_scope, finalize_unoptimized_compilation_data_list,
1384            jobs_to_retry_finalization_on_main_thread)) {
1385      return kNullMaybeHandle;
1386    }
1387  
1388    // Character stream shouldn't be used again.
1389    parse_info->ResetCharacterStream();
1390  
1391    return shared_info;
1392  }
1393  
1394  // TODO(leszeks): Remove this once off-thread finalization is always on.
CompileOnBackgroundThread(ParseInfo * parse_info,AccountingAllocator * allocator,UnoptimizedCompilationJobList * jobs)1395  void CompileOnBackgroundThread(ParseInfo* parse_info,
1396                                 AccountingAllocator* allocator,
1397                                 UnoptimizedCompilationJobList* jobs) {
1398    DisallowHeapAccess no_heap_access;
1399    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1400                 "V8.CompileCodeBackground");
1401    RuntimeCallTimerScope runtimeTimer(
1402        parse_info->runtime_call_stats(),
1403        RuntimeCallCounterIdForCompileBackground(parse_info));
1404  
1405    // Generate the unoptimized bytecode or asm-js data.
1406    DCHECK(jobs->empty());
1407  
1408    bool success = RecursivelyExecuteUnoptimizedCompilationJobs(
1409        parse_info, parse_info->literal(), allocator, jobs);
1410  
1411    USE(success);
1412    DCHECK_EQ(success, !jobs->empty());
1413  
1414    // Character stream shouldn't be used again.
1415    parse_info->ResetCharacterStream();
1416  }
1417  
CompileToplevel(ParseInfo * parse_info,Handle<Script> script,Isolate * isolate,IsCompiledScope * is_compiled_scope)1418  MaybeHandle<SharedFunctionInfo> CompileToplevel(
1419      ParseInfo* parse_info, Handle<Script> script, Isolate* isolate,
1420      IsCompiledScope* is_compiled_scope) {
1421    return CompileToplevel(parse_info, script, kNullMaybeHandle, isolate,
1422                           is_compiled_scope);
1423  }
1424  
1425  }  // namespace
1426  
~CompilationHandleScope()1427  CompilationHandleScope::~CompilationHandleScope() {
1428    info_->set_persistent_handles(persistent_.Detach());
1429  }
1430  
FinalizeUnoptimizedCompilationData(LocalIsolate * isolate,Handle<SharedFunctionInfo> function_handle,MaybeHandle<CoverageInfo> coverage_info,base::TimeDelta time_taken_to_execute,base::TimeDelta time_taken_to_finalize)1431  FinalizeUnoptimizedCompilationData::FinalizeUnoptimizedCompilationData(
1432      LocalIsolate* isolate, Handle<SharedFunctionInfo> function_handle,
1433      MaybeHandle<CoverageInfo> coverage_info,
1434      base::TimeDelta time_taken_to_execute,
1435      base::TimeDelta time_taken_to_finalize)
1436      : time_taken_to_execute_(time_taken_to_execute),
1437        time_taken_to_finalize_(time_taken_to_finalize),
1438        function_handle_(isolate->heap()->NewPersistentHandle(function_handle)),
1439        coverage_info_(isolate->heap()->NewPersistentMaybeHandle(coverage_info)) {
1440  }
1441  
DeferredFinalizationJobData(LocalIsolate * isolate,Handle<SharedFunctionInfo> function_handle,std::unique_ptr<UnoptimizedCompilationJob> job)1442  DeferredFinalizationJobData::DeferredFinalizationJobData(
1443      LocalIsolate* isolate, Handle<SharedFunctionInfo> function_handle,
1444      std::unique_ptr<UnoptimizedCompilationJob> job)
1445      : function_handle_(isolate->heap()->NewPersistentHandle(function_handle)),
1446        job_(std::move(job)) {}
1447  
BackgroundCompileTask(ScriptStreamingData * streamed_data,Isolate * isolate)1448  BackgroundCompileTask::BackgroundCompileTask(ScriptStreamingData* streamed_data,
1449                                               Isolate* isolate)
1450      : flags_(UnoptimizedCompileFlags::ForToplevelCompile(
1451            isolate, true, construct_language_mode(FLAG_use_strict),
1452            REPLMode::kNo)),
1453        compile_state_(isolate),
1454        info_(std::make_unique<ParseInfo>(isolate, flags_, &compile_state_)),
1455        isolate_for_local_isolate_(isolate),
1456        start_position_(0),
1457        end_position_(0),
1458        function_literal_id_(kFunctionLiteralIdTopLevel),
1459        stack_size_(i::FLAG_stack_size),
1460        worker_thread_runtime_call_stats_(
1461            isolate->counters()->worker_thread_runtime_call_stats()),
1462        timer_(isolate->counters()->compile_script_on_background()),
1463        language_mode_(info_->language_mode()) {
1464    VMState<PARSER> state(isolate);
1465  
1466    // Prepare the data for the internalization phase and compilation phase, which
1467    // will happen in the main thread after parsing.
1468  
1469    LOG(isolate, ScriptEvent(Logger::ScriptEventType::kStreamingCompile,
1470                             info_->flags().script_id()));
1471  
1472    std::unique_ptr<Utf16CharacterStream> stream(ScannerStream::For(
1473        streamed_data->source_stream.get(), streamed_data->encoding));
1474    info_->set_character_stream(std::move(stream));
1475  }
1476  
BackgroundCompileTask(const ParseInfo * outer_parse_info,const AstRawString * function_name,const FunctionLiteral * function_literal,WorkerThreadRuntimeCallStats * worker_thread_runtime_stats,TimedHistogram * timer,int max_stack_size)1477  BackgroundCompileTask::BackgroundCompileTask(
1478      const ParseInfo* outer_parse_info, const AstRawString* function_name,
1479      const FunctionLiteral* function_literal,
1480      WorkerThreadRuntimeCallStats* worker_thread_runtime_stats,
1481      TimedHistogram* timer, int max_stack_size)
1482      : flags_(UnoptimizedCompileFlags::ForToplevelFunction(
1483            outer_parse_info->flags(), function_literal)),
1484        compile_state_(*outer_parse_info->state()),
1485        info_(ParseInfo::ForToplevelFunction(flags_, &compile_state_,
1486                                             function_literal, function_name)),
1487        isolate_for_local_isolate_(nullptr),
1488        start_position_(function_literal->start_position()),
1489        end_position_(function_literal->end_position()),
1490        function_literal_id_(function_literal->function_literal_id()),
1491        stack_size_(max_stack_size),
1492        worker_thread_runtime_call_stats_(worker_thread_runtime_stats),
1493        timer_(timer),
1494        language_mode_(info_->language_mode()) {
1495    DCHECK_EQ(outer_parse_info->parameters_end_pos(), kNoSourcePosition);
1496    DCHECK_NULL(outer_parse_info->extension());
1497  
1498    DCHECK(!function_literal->is_toplevel());
1499  
1500    // Clone the character stream so both can be accessed independently.
1501    std::unique_ptr<Utf16CharacterStream> character_stream =
1502        outer_parse_info->character_stream()->Clone();
1503    character_stream->Seek(start_position_);
1504    info_->set_character_stream(std::move(character_stream));
1505  
1506    // Get preparsed scope data from the function literal.
1507    if (function_literal->produced_preparse_data()) {
1508      ZonePreparseData* serialized_data =
1509          function_literal->produced_preparse_data()->Serialize(info_->zone());
1510      info_->set_consumed_preparse_data(
1511          ConsumedPreparseData::For(info_->zone(), serialized_data));
1512    }
1513  }
1514  
1515  BackgroundCompileTask::~BackgroundCompileTask() = default;
1516  
1517  namespace {
1518  
1519  // A scope object that ensures a parse info's runtime call stats and stack limit
1520  // are set correctly during worker-thread compile, and restores it after going
1521  // out of scope.
1522  class OffThreadParseInfoScope {
1523   public:
OffThreadParseInfoScope(ParseInfo * parse_info,WorkerThreadRuntimeCallStats * worker_thread_runtime_stats,int stack_size)1524    OffThreadParseInfoScope(
1525        ParseInfo* parse_info,
1526        WorkerThreadRuntimeCallStats* worker_thread_runtime_stats, int stack_size)
1527        : parse_info_(parse_info),
1528          original_runtime_call_stats_(parse_info_->runtime_call_stats()),
1529          original_stack_limit_(parse_info_->stack_limit()),
1530          worker_thread_scope_(worker_thread_runtime_stats) {
1531      parse_info_->SetPerThreadState(GetCurrentStackPosition() - stack_size * KB,
1532                                     worker_thread_scope_.Get());
1533    }
1534  
~OffThreadParseInfoScope()1535    ~OffThreadParseInfoScope() {
1536      DCHECK_NOT_NULL(parse_info_);
1537      parse_info_->SetPerThreadState(original_stack_limit_,
1538                                     original_runtime_call_stats_);
1539    }
1540  
1541   private:
1542    ParseInfo* parse_info_;
1543    RuntimeCallStats* original_runtime_call_stats_;
1544    uintptr_t original_stack_limit_;
1545    WorkerThreadRuntimeCallStatsScope worker_thread_scope_;
1546  
1547    DISALLOW_COPY_AND_ASSIGN(OffThreadParseInfoScope);
1548  };
1549  
1550  }  // namespace
1551  
Run()1552  void BackgroundCompileTask::Run() {
1553    TimedHistogramScope timer(timer_);
1554    base::Optional<OffThreadParseInfoScope> off_thread_scope(
1555        base::in_place, info_.get(), worker_thread_runtime_call_stats_,
1556        stack_size_);
1557    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1558                 "BackgroundCompileTask::Run");
1559    RuntimeCallTimerScope runtimeTimer(
1560        info_->runtime_call_stats(),
1561        RuntimeCallCounterId::kCompileBackgroundCompileTask);
1562  
1563    // Update the character stream's runtime call stats.
1564    info_->character_stream()->set_runtime_call_stats(
1565        info_->runtime_call_stats());
1566  
1567    // Parser needs to stay alive for finalizing the parsing on the main
1568    // thread.
1569    parser_.reset(new Parser(info_.get()));
1570    parser_->InitializeEmptyScopeChain(info_.get());
1571  
1572    parser_->ParseOnBackground(info_.get(), start_position_, end_position_,
1573                               function_literal_id_);
1574  
1575    // Save the language mode.
1576    language_mode_ = info_->language_mode();
1577  
1578    if (!FLAG_finalize_streaming_on_background) {
1579      if (info_->literal() != nullptr) {
1580        CompileOnBackgroundThread(info_.get(), compile_state_.allocator(),
1581                                  &compilation_jobs_);
1582      }
1583    } else {
1584      DCHECK(info_->flags().is_toplevel());
1585  
1586      LocalIsolate isolate(isolate_for_local_isolate_, ThreadKind::kBackground);
1587      UnparkedScope unparked_scope(isolate.heap());
1588      LocalHandleScope handle_scope(&isolate);
1589  
1590      info_->ast_value_factory()->Internalize(&isolate);
1591  
1592      // We don't have the script source, origin, or details yet, so use default
1593      // values for them. These will be fixed up during the main-thread merge.
1594      Handle<Script> script =
1595          info_->CreateScript(&isolate, isolate.factory()->empty_string(),
1596                              kNullMaybeHandle, ScriptOriginOptions());
1597  
1598      parser_->HandleSourceURLComments(&isolate, script);
1599  
1600      MaybeHandle<SharedFunctionInfo> maybe_result;
1601      if (info_->literal() != nullptr) {
1602        maybe_result = CompileAndFinalizeOnBackgroundThread(
1603            info_.get(), compile_state_.allocator(), script, &isolate,
1604            &finalize_unoptimized_compilation_data_,
1605            &jobs_to_retry_finalization_on_main_thread_, &is_compiled_scope_);
1606      } else {
1607        DCHECK(compile_state_.pending_error_handler()->has_pending_error());
1608        PreparePendingException(&isolate, info_.get());
1609      }
1610  
1611      outer_function_sfi_ =
1612          isolate.heap()->NewPersistentMaybeHandle(maybe_result);
1613      script_ = isolate.heap()->NewPersistentHandle(script);
1614  
1615      persistent_handles_ = isolate.heap()->DetachPersistentHandles();
1616  
1617      {
1618        TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1619                     "V8.FinalizeCodeBackground.ReleaseParser");
1620        DCHECK_EQ(language_mode_, info_->language_mode());
1621        off_thread_scope.reset();
1622        parser_.reset();
1623        info_.reset();
1624      }
1625    }
1626  }
1627  
GetOuterFunctionSfi(Isolate * isolate)1628  MaybeHandle<SharedFunctionInfo> BackgroundCompileTask::GetOuterFunctionSfi(
1629      Isolate* isolate) {
1630    // outer_function_sfi_ is a persistent Handle, tied to the lifetime of the
1631    // persistent_handles_ member, so create a new Handle to let it outlive
1632    // the BackgroundCompileTask.
1633    Handle<SharedFunctionInfo> result;
1634    if (outer_function_sfi_.ToHandle(&result)) {
1635      return handle(*result, isolate);
1636    }
1637    return kNullMaybeHandle;
1638  }
1639  
GetScript(Isolate * isolate)1640  Handle<Script> BackgroundCompileTask::GetScript(Isolate* isolate) {
1641    // script_ is a persistent Handle, tied to the lifetime of the
1642    // persistent_handles_ member, so create a new Handle to let it outlive
1643    // the BackgroundCompileTask.
1644    return handle(*script_, isolate);
1645  }
1646  
1647  // ----------------------------------------------------------------------------
1648  // Implementation of Compiler
1649  
1650  // static
CollectSourcePositions(Isolate * isolate,Handle<SharedFunctionInfo> shared_info)1651  bool Compiler::CollectSourcePositions(Isolate* isolate,
1652                                        Handle<SharedFunctionInfo> shared_info) {
1653    DCHECK(shared_info->is_compiled());
1654    DCHECK(shared_info->HasBytecodeArray());
1655    DCHECK(!shared_info->GetBytecodeArray().HasSourcePositionTable());
1656  
1657    // Source position collection should be context independent.
1658    NullContextScope null_context_scope(isolate);
1659  
1660    // Collecting source positions requires allocating a new source position
1661    // table.
1662    DCHECK(AllowHeapAllocation::IsAllowed());
1663    DCHECK(AllowGarbageCollection::IsAllowed());
1664  
1665    Handle<BytecodeArray> bytecode =
1666        handle(shared_info->GetBytecodeArray(), isolate);
1667  
1668    // TODO(v8:8510): Push the CLEAR_EXCEPTION flag or something like it down into
1669    // the parser so it aborts without setting a pending exception, which then
1670    // gets thrown. This would avoid the situation where potentially we'd reparse
1671    // several times (running out of stack each time) before hitting this limit.
1672    if (GetCurrentStackPosition() < isolate->stack_guard()->real_climit()) {
1673      // Stack is already exhausted.
1674      bytecode->SetSourcePositionsFailedToCollect();
1675      return false;
1676    }
1677  
1678    DCHECK(AllowCompilation::IsAllowed(isolate));
1679    DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
1680    DCHECK(!isolate->has_pending_exception());
1681    VMState<BYTECODE_COMPILER> state(isolate);
1682    PostponeInterruptsScope postpone(isolate);
1683    RuntimeCallTimerScope runtimeTimer(
1684        isolate, RuntimeCallCounterId::kCompileCollectSourcePositions);
1685    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1686                 "V8.CollectSourcePositions");
1687    HistogramTimerScope timer(isolate->counters()->collect_source_positions());
1688  
1689    // Set up parse info.
1690    UnoptimizedCompileFlags flags =
1691        UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared_info);
1692    flags.set_is_lazy_compile(true);
1693    flags.set_collect_source_positions(true);
1694    flags.set_allow_natives_syntax(FLAG_allow_natives_syntax);
1695  
1696    UnoptimizedCompileState compile_state(isolate);
1697    ParseInfo parse_info(isolate, flags, &compile_state);
1698  
1699    // Parse and update ParseInfo with the results. Don't update parsing
1700    // statistics since we've already parsed the code before.
1701    if (!parsing::ParseAny(&parse_info, shared_info, isolate,
1702                           parsing::ReportStatisticsMode::kNo)) {
1703      // Parsing failed probably as a result of stack exhaustion.
1704      bytecode->SetSourcePositionsFailedToCollect();
1705      return FailAndClearPendingException(isolate);
1706    }
1707  
1708    // Character stream shouldn't be used again.
1709    parse_info.ResetCharacterStream();
1710  
1711    // Generate the unoptimized bytecode.
1712    // TODO(v8:8510): Consider forcing preparsing of inner functions to avoid
1713    // wasting time fully parsing them when they won't ever be used.
1714    std::unique_ptr<UnoptimizedCompilationJob> job;
1715    {
1716      job = interpreter::Interpreter::NewSourcePositionCollectionJob(
1717          &parse_info, parse_info.literal(), bytecode, isolate->allocator());
1718  
1719      if (!job || job->ExecuteJob() != CompilationJob::SUCCEEDED ||
1720          job->FinalizeJob(shared_info, isolate) != CompilationJob::SUCCEEDED) {
1721        // Recompiling failed probably as a result of stack exhaustion.
1722        bytecode->SetSourcePositionsFailedToCollect();
1723        return FailAndClearPendingException(isolate);
1724      }
1725    }
1726  
1727    DCHECK(job->compilation_info()->flags().collect_source_positions());
1728  
1729    // If debugging, make sure that instrumented bytecode has the source position
1730    // table set on it as well.
1731    if (shared_info->HasDebugInfo() &&
1732        shared_info->GetDebugInfo().HasInstrumentedBytecodeArray()) {
1733      ByteArray source_position_table =
1734          job->compilation_info()->bytecode_array()->SourcePositionTable();
1735      shared_info->GetDebugBytecodeArray().set_source_position_table(
1736          source_position_table, kReleaseStore);
1737    }
1738  
1739    DCHECK(!isolate->has_pending_exception());
1740    DCHECK(shared_info->is_compiled_scope(isolate).is_compiled());
1741    return true;
1742  }
1743  
1744  // static
Compile(Handle<SharedFunctionInfo> shared_info,ClearExceptionFlag flag,IsCompiledScope * is_compiled_scope)1745  bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
1746                         ClearExceptionFlag flag,
1747                         IsCompiledScope* is_compiled_scope) {
1748    // We should never reach here if the function is already compiled.
1749    DCHECK(!shared_info->is_compiled());
1750    DCHECK(!is_compiled_scope->is_compiled());
1751  
1752    Isolate* isolate = shared_info->GetIsolate();
1753    DCHECK(AllowCompilation::IsAllowed(isolate));
1754    DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
1755    DCHECK(!isolate->has_pending_exception());
1756    DCHECK(!shared_info->HasBytecodeArray());
1757    VMState<BYTECODE_COMPILER> state(isolate);
1758    PostponeInterruptsScope postpone(isolate);
1759    TimerEventScope<TimerEventCompileCode> compile_timer(isolate);
1760    RuntimeCallTimerScope runtimeTimer(isolate,
1761                                       RuntimeCallCounterId::kCompileFunction);
1762    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
1763    AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
1764  
1765    Handle<Script> script(Script::cast(shared_info->script()), isolate);
1766  
1767    // Set up parse info.
1768    UnoptimizedCompileFlags flags =
1769        UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared_info);
1770    flags.set_is_lazy_compile(true);
1771  
1772    UnoptimizedCompileState compile_state(isolate);
1773    ParseInfo parse_info(isolate, flags, &compile_state);
1774  
1775    // Check if the compiler dispatcher has shared_info enqueued for compile.
1776    CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
1777    if (dispatcher->IsEnqueued(shared_info)) {
1778      if (!dispatcher->FinishNow(shared_info)) {
1779        return FailWithPendingException(isolate, script, &parse_info, flag);
1780      }
1781      *is_compiled_scope = shared_info->is_compiled_scope(isolate);
1782      DCHECK(is_compiled_scope->is_compiled());
1783      return true;
1784    }
1785  
1786    if (shared_info->HasUncompiledDataWithPreparseData()) {
1787      parse_info.set_consumed_preparse_data(ConsumedPreparseData::For(
1788          isolate,
1789          handle(
1790              shared_info->uncompiled_data_with_preparse_data().preparse_data(),
1791              isolate)));
1792    }
1793  
1794    // Parse and update ParseInfo with the results.
1795    if (!parsing::ParseAny(&parse_info, shared_info, isolate,
1796                           parsing::ReportStatisticsMode::kYes)) {
1797      return FailWithPendingException(isolate, script, &parse_info, flag);
1798    }
1799  
1800    // Generate the unoptimized bytecode or asm-js data.
1801    FinalizeUnoptimizedCompilationDataList
1802        finalize_unoptimized_compilation_data_list;
1803  
1804    if (!IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs(
1805            isolate, shared_info, script, &parse_info, isolate->allocator(),
1806            is_compiled_scope, &finalize_unoptimized_compilation_data_list,
1807            nullptr)) {
1808      return FailWithPendingException(isolate, script, &parse_info, flag);
1809    }
1810  
1811    FinalizeUnoptimizedCompilation(isolate, script, flags, &compile_state,
1812                                   finalize_unoptimized_compilation_data_list);
1813  
1814    DCHECK(!isolate->has_pending_exception());
1815    DCHECK(is_compiled_scope->is_compiled());
1816    return true;
1817  }
1818  
1819  // static
Compile(Handle<JSFunction> function,ClearExceptionFlag flag,IsCompiledScope * is_compiled_scope)1820  bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag,
1821                         IsCompiledScope* is_compiled_scope) {
1822    // We should never reach here if the function is already compiled or
1823    // optimized.
1824    DCHECK(!function->is_compiled());
1825    DCHECK(!function->HasOptimizationMarker());
1826    DCHECK(!function->HasAvailableOptimizedCode());
1827  
1828    // Reset the JSFunction if we are recompiling due to the bytecode having been
1829    // flushed.
1830    function->ResetIfBytecodeFlushed();
1831  
1832    Isolate* isolate = function->GetIsolate();
1833    Handle<SharedFunctionInfo> shared_info = handle(function->shared(), isolate);
1834  
1835    // Ensure shared function info is compiled.
1836    *is_compiled_scope = shared_info->is_compiled_scope(isolate);
1837    if (!is_compiled_scope->is_compiled() &&
1838        !Compile(shared_info, flag, is_compiled_scope)) {
1839      return false;
1840    }
1841    DCHECK(is_compiled_scope->is_compiled());
1842    Handle<Code> code = handle(shared_info->GetCode(), isolate);
1843  
1844    // Initialize the feedback cell for this JSFunction.
1845    JSFunction::InitializeFeedbackCell(function, is_compiled_scope);
1846  
1847    // Optimize now if --always-opt is enabled.
1848    if (FLAG_always_opt && !function->shared().HasAsmWasmData()) {
1849      CompilerTracer::TraceOptimizeForAlwaysOpt(isolate, function,
1850                                                CodeKindForTopTier());
1851  
1852      Handle<Code> maybe_code;
1853      if (GetOptimizedCode(function, ConcurrencyMode::kNotConcurrent,
1854                           CodeKindForTopTier())
1855              .ToHandle(&maybe_code)) {
1856        code = maybe_code;
1857      }
1858    }
1859  
1860    // Install code on closure.
1861    function->set_code(*code);
1862  
1863    // Check postconditions on success.
1864    DCHECK(!isolate->has_pending_exception());
1865    DCHECK(function->shared().is_compiled());
1866    DCHECK(function->is_compiled());
1867    return true;
1868  }
1869  
1870  // static
FinalizeBackgroundCompileTask(BackgroundCompileTask * task,Handle<SharedFunctionInfo> shared_info,Isolate * isolate,ClearExceptionFlag flag)1871  bool Compiler::FinalizeBackgroundCompileTask(
1872      BackgroundCompileTask* task, Handle<SharedFunctionInfo> shared_info,
1873      Isolate* isolate, ClearExceptionFlag flag) {
1874    DCHECK(!FLAG_finalize_streaming_on_background);
1875  
1876    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1877                 "V8.FinalizeBackgroundCompileTask");
1878    RuntimeCallTimerScope runtimeTimer(
1879        isolate, RuntimeCallCounterId::kCompileFinalizeBackgroundCompileTask);
1880    HandleScope scope(isolate);
1881    ParseInfo* parse_info = task->info();
1882    DCHECK(!parse_info->flags().is_toplevel());
1883    DCHECK(!shared_info->is_compiled());
1884  
1885    Handle<Script> script(Script::cast(shared_info->script()), isolate);
1886    parse_info->CheckFlagsForFunctionFromScript(*script);
1887  
1888    task->parser()->UpdateStatistics(isolate, script);
1889    task->parser()->HandleSourceURLComments(isolate, script);
1890  
1891    if (task->compilation_jobs()->empty()) {
1892      // Parsing or compile failed on background thread - report error messages.
1893      return FailWithPendingException(isolate, script, parse_info, flag);
1894    }
1895  
1896    // Parsing has succeeded - finalize compilation.
1897    parse_info->ast_value_factory()->Internalize(isolate);
1898    if (!FinalizeAllUnoptimizedCompilationJobs(
1899            parse_info, isolate, script, task->compilation_jobs(),
1900            task->finalize_unoptimized_compilation_data())) {
1901      // Finalization failed - throw an exception.
1902      return FailWithPendingException(isolate, script, parse_info, flag);
1903    }
1904    FinalizeUnoptimizedCompilation(
1905        isolate, script, parse_info->flags(), parse_info->state(),
1906        *task->finalize_unoptimized_compilation_data());
1907  
1908    DCHECK(!isolate->has_pending_exception());
1909    DCHECK(shared_info->is_compiled());
1910    return true;
1911  }
1912  
1913  // static
CompileOptimized(Handle<JSFunction> function,ConcurrencyMode mode,CodeKind code_kind)1914  bool Compiler::CompileOptimized(Handle<JSFunction> function,
1915                                  ConcurrencyMode mode, CodeKind code_kind) {
1916    DCHECK(CodeKindIsOptimizedJSFunction(code_kind));
1917  
1918    // If the requested code kind is already available, do nothing.
1919    if (function->HasAvailableCodeKind(code_kind)) return true;
1920  
1921    Isolate* isolate = function->GetIsolate();
1922    DCHECK(AllowCompilation::IsAllowed(isolate));
1923  
1924    Handle<Code> code;
1925    if (!GetOptimizedCode(function, mode, code_kind).ToHandle(&code)) {
1926      // Optimization failed, get unoptimized code. Unoptimized code must exist
1927      // already if we are optimizing.
1928      DCHECK(!isolate->has_pending_exception());
1929      DCHECK(function->shared().is_compiled());
1930      DCHECK(function->shared().IsInterpreted());
1931      code = BUILTIN_CODE(isolate, InterpreterEntryTrampoline);
1932    }
1933  
1934    if (!IsForNativeContextIndependentCachingOnly(code_kind)) {
1935      function->set_code(*code);
1936    }
1937  
1938    // Check postconditions on success.
1939    DCHECK(!isolate->has_pending_exception());
1940    DCHECK(function->shared().is_compiled());
1941    DCHECK(function->is_compiled());
1942    if (UsesOptimizationMarker(code_kind)) {
1943      DCHECK_IMPLIES(function->HasOptimizationMarker(),
1944                     function->IsInOptimizationQueue());
1945      DCHECK_IMPLIES(function->HasOptimizationMarker(),
1946                     function->ChecksOptimizationMarker());
1947      DCHECK_IMPLIES(function->IsInOptimizationQueue(),
1948                     mode == ConcurrencyMode::kConcurrent);
1949    }
1950    return true;
1951  }
1952  
1953  // static
CompileForLiveEdit(ParseInfo * parse_info,Handle<Script> script,Isolate * isolate)1954  MaybeHandle<SharedFunctionInfo> Compiler::CompileForLiveEdit(
1955      ParseInfo* parse_info, Handle<Script> script, Isolate* isolate) {
1956    IsCompiledScope is_compiled_scope;
1957    return CompileToplevel(parse_info, script, isolate, &is_compiled_scope);
1958  }
1959  
1960  // static
GetFunctionFromEval(Handle<String> source,Handle<SharedFunctionInfo> outer_info,Handle<Context> context,LanguageMode language_mode,ParseRestriction restriction,int parameters_end_pos,int eval_scope_position,int eval_position)1961  MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
1962      Handle<String> source, Handle<SharedFunctionInfo> outer_info,
1963      Handle<Context> context, LanguageMode language_mode,
1964      ParseRestriction restriction, int parameters_end_pos,
1965      int eval_scope_position, int eval_position) {
1966    Isolate* isolate = context->GetIsolate();
1967    int source_length = source->length();
1968    isolate->counters()->total_eval_size()->Increment(source_length);
1969    isolate->counters()->total_compile_size()->Increment(source_length);
1970  
1971    // The cache lookup key needs to be aware of the separation between the
1972    // parameters and the body to prevent this valid invocation:
1973    //   Function("", "function anonymous(\n/**/) {\n}");
1974    // from adding an entry that falsely approves this invalid invocation:
1975    //   Function("\n/**/) {\nfunction anonymous(", "}");
1976    // The actual eval_scope_position for indirect eval and CreateDynamicFunction
1977    // is unused (just 0), which means it's an available field to use to indicate
1978    // this separation. But to make sure we're not causing other false hits, we
1979    // negate the scope position.
1980    if (restriction == ONLY_SINGLE_FUNCTION_LITERAL &&
1981        parameters_end_pos != kNoSourcePosition) {
1982      // use the parameters_end_pos as the eval_scope_position in the eval cache.
1983      DCHECK_EQ(eval_scope_position, 0);
1984      eval_scope_position = -parameters_end_pos;
1985    }
1986    CompilationCache* compilation_cache = isolate->compilation_cache();
1987    InfoCellPair eval_result = compilation_cache->LookupEval(
1988        source, outer_info, context, language_mode, eval_scope_position);
1989    Handle<FeedbackCell> feedback_cell;
1990    if (eval_result.has_feedback_cell()) {
1991      feedback_cell = handle(eval_result.feedback_cell(), isolate);
1992    }
1993  
1994    Handle<SharedFunctionInfo> shared_info;
1995    Handle<Script> script;
1996    IsCompiledScope is_compiled_scope;
1997    bool allow_eval_cache;
1998    if (eval_result.has_shared()) {
1999      shared_info = Handle<SharedFunctionInfo>(eval_result.shared(), isolate);
2000      script = Handle<Script>(Script::cast(shared_info->script()), isolate);
2001      is_compiled_scope = shared_info->is_compiled_scope(isolate);
2002      allow_eval_cache = true;
2003    } else {
2004      UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile(
2005          isolate, true, language_mode, REPLMode::kNo);
2006      flags.set_is_eval(true);
2007      flags.set_parse_restriction(restriction);
2008  
2009      UnoptimizedCompileState compile_state(isolate);
2010      ParseInfo parse_info(isolate, flags, &compile_state);
2011      parse_info.set_parameters_end_pos(parameters_end_pos);
2012      DCHECK(!parse_info.flags().is_module());
2013  
2014      MaybeHandle<ScopeInfo> maybe_outer_scope_info;
2015      if (!context->IsNativeContext()) {
2016        maybe_outer_scope_info = handle(context->scope_info(), isolate);
2017      }
2018      script =
2019          parse_info.CreateScript(isolate, source, kNullMaybeHandle,
2020                                  OriginOptionsForEval(outer_info->script()));
2021      script->set_eval_from_shared(*outer_info);
2022      if (eval_position == kNoSourcePosition) {
2023        // If the position is missing, attempt to get the code offset by
2024        // walking the stack. Do not translate the code offset into source
2025        // position, but store it as negative value for lazy translation.
2026        StackTraceFrameIterator it(isolate);
2027        if (!it.done() && it.is_javascript()) {
2028          FrameSummary summary = FrameSummary::GetTop(it.javascript_frame());
2029          script->set_eval_from_shared(
2030              summary.AsJavaScript().function()->shared());
2031          script->set_origin_options(OriginOptionsForEval(*summary.script()));
2032          eval_position = -summary.code_offset();
2033        } else {
2034          eval_position = 0;
2035        }
2036      }
2037      script->set_eval_from_position(eval_position);
2038  
2039      if (!CompileToplevel(&parse_info, script, maybe_outer_scope_info, isolate,
2040                           &is_compiled_scope)
2041               .ToHandle(&shared_info)) {
2042        return MaybeHandle<JSFunction>();
2043      }
2044      allow_eval_cache = parse_info.allow_eval_cache();
2045    }
2046  
2047    // If caller is strict mode, the result must be in strict mode as well.
2048    DCHECK(is_sloppy(language_mode) || is_strict(shared_info->language_mode()));
2049  
2050    Handle<JSFunction> result;
2051    if (eval_result.has_shared()) {
2052      if (eval_result.has_feedback_cell()) {
2053        result = isolate->factory()->NewFunctionFromSharedFunctionInfo(
2054            shared_info, context, feedback_cell, AllocationType::kYoung);
2055      } else {
2056        result = isolate->factory()->NewFunctionFromSharedFunctionInfo(
2057            shared_info, context, AllocationType::kYoung);
2058        JSFunction::InitializeFeedbackCell(result, &is_compiled_scope);
2059        if (allow_eval_cache) {
2060          // Make sure to cache this result.
2061          Handle<FeedbackCell> new_feedback_cell(result->raw_feedback_cell(),
2062                                                 isolate);
2063          compilation_cache->PutEval(source, outer_info, context, shared_info,
2064                                     new_feedback_cell, eval_scope_position);
2065        }
2066      }
2067    } else {
2068      result = isolate->factory()->NewFunctionFromSharedFunctionInfo(
2069          shared_info, context, AllocationType::kYoung);
2070      JSFunction::InitializeFeedbackCell(result, &is_compiled_scope);
2071      if (allow_eval_cache) {
2072        // Add the SharedFunctionInfo and the LiteralsArray to the eval cache if
2073        // we didn't retrieve from there.
2074        Handle<FeedbackCell> new_feedback_cell(result->raw_feedback_cell(),
2075                                               isolate);
2076        compilation_cache->PutEval(source, outer_info, context, shared_info,
2077                                   new_feedback_cell, eval_scope_position);
2078      }
2079    }
2080    DCHECK(is_compiled_scope.is_compiled());
2081  
2082    return result;
2083  }
2084  
2085  // Check whether embedder allows code generation in this context.
2086  // (via v8::Isolate::SetAllowCodeGenerationFromStringsCallback)
CodeGenerationFromStringsAllowed(Isolate * isolate,Handle<Context> context,Handle<String> source)2087  bool CodeGenerationFromStringsAllowed(Isolate* isolate, Handle<Context> context,
2088                                        Handle<String> source) {
2089    DCHECK(context->allow_code_gen_from_strings().IsFalse(isolate));
2090    DCHECK(isolate->allow_code_gen_callback());
2091  
2092    // Callback set. Let it decide if code generation is allowed.
2093    VMState<EXTERNAL> state(isolate);
2094    RuntimeCallTimerScope timer(
2095        isolate, RuntimeCallCounterId::kCodeGenerationFromStringsCallbacks);
2096    AllowCodeGenerationFromStringsCallback callback =
2097        isolate->allow_code_gen_callback();
2098    return callback(v8::Utils::ToLocal(context), v8::Utils::ToLocal(source));
2099  }
2100  
2101  // Check whether embedder allows code generation in this context.
2102  // (via v8::Isolate::SetModifyCodeGenerationFromStringsCallback
2103  //  or v8::Isolate::SetModifyCodeGenerationFromStringsCallback2)
ModifyCodeGenerationFromStrings(Isolate * isolate,Handle<Context> context,Handle<i::Object> * source,bool is_code_like)2104  bool ModifyCodeGenerationFromStrings(Isolate* isolate, Handle<Context> context,
2105                                       Handle<i::Object>* source,
2106                                       bool is_code_like) {
2107    DCHECK(isolate->modify_code_gen_callback() ||
2108           isolate->modify_code_gen_callback2());
2109    DCHECK(source);
2110  
2111    // Callback set. Run it, and use the return value as source, or block
2112    // execution if it's not set.
2113    VMState<EXTERNAL> state(isolate);
2114    RuntimeCallTimerScope timer(
2115        isolate, RuntimeCallCounterId::kCodeGenerationFromStringsCallbacks);
2116    ModifyCodeGenerationFromStringsResult result =
2117        isolate->modify_code_gen_callback()
2118            ? isolate->modify_code_gen_callback()(v8::Utils::ToLocal(context),
2119                                                  v8::Utils::ToLocal(*source))
2120            : isolate->modify_code_gen_callback2()(v8::Utils::ToLocal(context),
2121                                                   v8::Utils::ToLocal(*source),
2122                                                   is_code_like);
2123    if (result.codegen_allowed && !result.modified_source.IsEmpty()) {
2124      // Use the new source (which might be the same as the old source).
2125      *source =
2126          Utils::OpenHandle(*result.modified_source.ToLocalChecked(), false);
2127    }
2128    return result.codegen_allowed;
2129  }
2130  
2131  // Run Embedder-mandated checks before generating code from a string.
2132  //
2133  // Returns a string to be used for compilation, or a flag that an object type
2134  // was encountered that is neither a string, nor something the embedder knows
2135  // how to handle.
2136  //
2137  // Returns: (assuming: std::tie(source, unknown_object))
2138  // - !source.is_null(): compilation allowed, source contains the source string.
2139  // - unknown_object is true: compilation allowed, but we don't know how to
2140  //                           deal with source_object.
2141  // - source.is_null() && !unknown_object: compilation should be blocked.
2142  //
2143  // - !source_is_null() and unknown_object can't be true at the same time.
2144  
2145  // static
ValidateDynamicCompilationSource(Isolate * isolate,Handle<Context> context,Handle<i::Object> original_source,bool is_code_like)2146  std::pair<MaybeHandle<String>, bool> Compiler::ValidateDynamicCompilationSource(
2147      Isolate* isolate, Handle<Context> context,
2148      Handle<i::Object> original_source, bool is_code_like) {
2149    // Check if the context unconditionally allows code gen from strings.
2150    // allow_code_gen_from_strings can be many things, so we'll always check
2151    // against the 'false' literal, so that e.g. undefined and 'true' are treated
2152    // the same.
2153    if (!context->allow_code_gen_from_strings().IsFalse(isolate) &&
2154        original_source->IsString()) {
2155      return {Handle<String>::cast(original_source), false};
2156    }
2157  
2158    // Check if the context allows code generation for this string.
2159    // allow_code_gen_callback only allows proper strings.
2160    // (I.e., let allow_code_gen_callback decide, if it has been set.)
2161    if (isolate->allow_code_gen_callback()) {
2162      // If we run into this condition, the embedder has marked some object
2163      // templates as "code like", but has given us a callback that only accepts
2164      // strings. That makes no sense.
2165      DCHECK(!original_source->IsCodeLike(isolate));
2166  
2167      if (!original_source->IsString()) {
2168        return {MaybeHandle<String>(), true};
2169      }
2170      Handle<String> string_source = Handle<String>::cast(original_source);
2171      if (!CodeGenerationFromStringsAllowed(isolate, context, string_source)) {
2172        return {MaybeHandle<String>(), false};
2173      }
2174      return {string_source, false};
2175    }
2176  
2177    // Check if the context wants to block or modify this source object.
2178    // Double-check that we really have a string now.
2179    // (Let modify_code_gen_callback decide, if it's been set.)
2180    if (isolate->modify_code_gen_callback() ||
2181        isolate->modify_code_gen_callback2()) {
2182      Handle<i::Object> modified_source = original_source;
2183      if (!ModifyCodeGenerationFromStrings(isolate, context, &modified_source,
2184                                           is_code_like)) {
2185        return {MaybeHandle<String>(), false};
2186      }
2187      if (!modified_source->IsString()) {
2188        return {MaybeHandle<String>(), true};
2189      }
2190      return {Handle<String>::cast(modified_source), false};
2191    }
2192  
2193    if (!context->allow_code_gen_from_strings().IsFalse(isolate) &&
2194        original_source->IsCodeLike(isolate)) {
2195      // Codegen is unconditionally allowed, and we're been given a CodeLike
2196      // object. Stringify.
2197      MaybeHandle<String> stringified_source =
2198          Object::ToString(isolate, original_source);
2199      return {stringified_source, stringified_source.is_null()};
2200    }
2201  
2202    // If unconditional codegen was disabled, and no callback defined, we block
2203    // strings and allow all other objects.
2204    return {MaybeHandle<String>(), !original_source->IsString()};
2205  }
2206  
2207  // static
GetFunctionFromValidatedString(Handle<Context> context,MaybeHandle<String> source,ParseRestriction restriction,int parameters_end_pos)2208  MaybeHandle<JSFunction> Compiler::GetFunctionFromValidatedString(
2209      Handle<Context> context, MaybeHandle<String> source,
2210      ParseRestriction restriction, int parameters_end_pos) {
2211    Isolate* const isolate = context->GetIsolate();
2212    Handle<Context> native_context(context->native_context(), isolate);
2213  
2214    // Raise an EvalError if we did not receive a string.
2215    if (source.is_null()) {
2216      Handle<Object> error_message =
2217          native_context->ErrorMessageForCodeGenerationFromStrings();
2218      THROW_NEW_ERROR(
2219          isolate,
2220          NewEvalError(MessageTemplate::kCodeGenFromStrings, error_message),
2221          JSFunction);
2222    }
2223  
2224    // Compile source string in the native context.
2225    int eval_scope_position = 0;
2226    int eval_position = kNoSourcePosition;
2227    Handle<SharedFunctionInfo> outer_info(
2228        native_context->empty_function().shared(), isolate);
2229    return Compiler::GetFunctionFromEval(source.ToHandleChecked(), outer_info,
2230                                         native_context, LanguageMode::kSloppy,
2231                                         restriction, parameters_end_pos,
2232                                         eval_scope_position, eval_position);
2233  }
2234  
2235  // static
GetFunctionFromString(Handle<Context> context,Handle<Object> source,ParseRestriction restriction,int parameters_end_pos,bool is_code_like)2236  MaybeHandle<JSFunction> Compiler::GetFunctionFromString(
2237      Handle<Context> context, Handle<Object> source,
2238      ParseRestriction restriction, int parameters_end_pos, bool is_code_like) {
2239    Isolate* const isolate = context->GetIsolate();
2240    MaybeHandle<String> validated_source =
2241        ValidateDynamicCompilationSource(isolate, context, source, is_code_like)
2242            .first;
2243    return GetFunctionFromValidatedString(context, validated_source, restriction,
2244                                          parameters_end_pos);
2245  }
2246  
2247  namespace {
2248  
2249  struct ScriptCompileTimerScope {
2250   public:
2251    // TODO(leszeks): There are too many blink-specific entries in this enum,
2252    // figure out a way to push produce/hit-isolate-cache/consume/consume-failed
2253    // back up the API and log them in blink instead.
2254    enum class CacheBehaviour {
2255      kProduceCodeCache,
2256      kHitIsolateCacheWhenNoCache,
2257      kConsumeCodeCache,
2258      kConsumeCodeCacheFailed,
2259      kNoCacheBecauseInlineScript,
2260      kNoCacheBecauseScriptTooSmall,
2261      kNoCacheBecauseCacheTooCold,
2262      kNoCacheNoReason,
2263      kNoCacheBecauseNoResource,
2264      kNoCacheBecauseInspector,
2265      kNoCacheBecauseCachingDisabled,
2266      kNoCacheBecauseModule,
2267      kNoCacheBecauseStreamingSource,
2268      kNoCacheBecauseV8Extension,
2269      kHitIsolateCacheWhenProduceCodeCache,
2270      kHitIsolateCacheWhenConsumeCodeCache,
2271      kNoCacheBecauseExtensionModule,
2272      kNoCacheBecausePacScript,
2273      kNoCacheBecauseInDocumentWrite,
2274      kNoCacheBecauseResourceWithNoCacheHandler,
2275      kHitIsolateCacheWhenStreamingSource,
2276      kCount
2277    };
2278  
ScriptCompileTimerScopev8::internal::__anon75b411e30611::ScriptCompileTimerScope2279    explicit ScriptCompileTimerScope(
2280        Isolate* isolate, ScriptCompiler::NoCacheReason no_cache_reason)
2281        : isolate_(isolate),
2282          all_scripts_histogram_scope_(isolate->counters()->compile_script(),
2283                                       true),
2284          no_cache_reason_(no_cache_reason),
2285          hit_isolate_cache_(false),
2286          producing_code_cache_(false),
2287          consuming_code_cache_(false),
2288          consuming_code_cache_failed_(false) {}
2289  
~ScriptCompileTimerScopev8::internal::__anon75b411e30611::ScriptCompileTimerScope2290    ~ScriptCompileTimerScope() {
2291      CacheBehaviour cache_behaviour = GetCacheBehaviour();
2292  
2293      Histogram* cache_behaviour_histogram =
2294          isolate_->counters()->compile_script_cache_behaviour();
2295      // Sanity check that the histogram has exactly one bin per enum entry.
2296      DCHECK_EQ(0, cache_behaviour_histogram->min());
2297      DCHECK_EQ(static_cast<int>(CacheBehaviour::kCount),
2298                cache_behaviour_histogram->max() + 1);
2299      DCHECK_EQ(static_cast<int>(CacheBehaviour::kCount),
2300                cache_behaviour_histogram->num_buckets());
2301      cache_behaviour_histogram->AddSample(static_cast<int>(cache_behaviour));
2302  
2303      histogram_scope_.set_histogram(
2304          GetCacheBehaviourTimedHistogram(cache_behaviour));
2305    }
2306  
set_hit_isolate_cachev8::internal::__anon75b411e30611::ScriptCompileTimerScope2307    void set_hit_isolate_cache() { hit_isolate_cache_ = true; }
2308  
set_producing_code_cachev8::internal::__anon75b411e30611::ScriptCompileTimerScope2309    void set_producing_code_cache() { producing_code_cache_ = true; }
2310  
set_consuming_code_cachev8::internal::__anon75b411e30611::ScriptCompileTimerScope2311    void set_consuming_code_cache() { consuming_code_cache_ = true; }
2312  
set_consuming_code_cache_failedv8::internal::__anon75b411e30611::ScriptCompileTimerScope2313    void set_consuming_code_cache_failed() {
2314      consuming_code_cache_failed_ = true;
2315    }
2316  
2317   private:
2318    Isolate* isolate_;
2319    LazyTimedHistogramScope histogram_scope_;
2320    // TODO(leszeks): This timer is the sum of the other times, consider removing
2321    // it to save space.
2322    HistogramTimerScope all_scripts_histogram_scope_;
2323    ScriptCompiler::NoCacheReason no_cache_reason_;
2324    bool hit_isolate_cache_;
2325    bool producing_code_cache_;
2326    bool consuming_code_cache_;
2327    bool consuming_code_cache_failed_;
2328  
GetCacheBehaviourv8::internal::__anon75b411e30611::ScriptCompileTimerScope2329    CacheBehaviour GetCacheBehaviour() {
2330      if (producing_code_cache_) {
2331        if (hit_isolate_cache_) {
2332          return CacheBehaviour::kHitIsolateCacheWhenProduceCodeCache;
2333        } else {
2334          return CacheBehaviour::kProduceCodeCache;
2335        }
2336      }
2337  
2338      if (consuming_code_cache_) {
2339        if (hit_isolate_cache_) {
2340          return CacheBehaviour::kHitIsolateCacheWhenConsumeCodeCache;
2341        } else if (consuming_code_cache_failed_) {
2342          return CacheBehaviour::kConsumeCodeCacheFailed;
2343        }
2344        return CacheBehaviour::kConsumeCodeCache;
2345      }
2346  
2347      if (hit_isolate_cache_) {
2348        if (no_cache_reason_ == ScriptCompiler::kNoCacheBecauseStreamingSource) {
2349          return CacheBehaviour::kHitIsolateCacheWhenStreamingSource;
2350        }
2351        return CacheBehaviour::kHitIsolateCacheWhenNoCache;
2352      }
2353  
2354      switch (no_cache_reason_) {
2355        case ScriptCompiler::kNoCacheBecauseInlineScript:
2356          return CacheBehaviour::kNoCacheBecauseInlineScript;
2357        case ScriptCompiler::kNoCacheBecauseScriptTooSmall:
2358          return CacheBehaviour::kNoCacheBecauseScriptTooSmall;
2359        case ScriptCompiler::kNoCacheBecauseCacheTooCold:
2360          return CacheBehaviour::kNoCacheBecauseCacheTooCold;
2361        case ScriptCompiler::kNoCacheNoReason:
2362          return CacheBehaviour::kNoCacheNoReason;
2363        case ScriptCompiler::kNoCacheBecauseNoResource:
2364          return CacheBehaviour::kNoCacheBecauseNoResource;
2365        case ScriptCompiler::kNoCacheBecauseInspector:
2366          return CacheBehaviour::kNoCacheBecauseInspector;
2367        case ScriptCompiler::kNoCacheBecauseCachingDisabled:
2368          return CacheBehaviour::kNoCacheBecauseCachingDisabled;
2369        case ScriptCompiler::kNoCacheBecauseModule:
2370          return CacheBehaviour::kNoCacheBecauseModule;
2371        case ScriptCompiler::kNoCacheBecauseStreamingSource:
2372          return CacheBehaviour::kNoCacheBecauseStreamingSource;
2373        case ScriptCompiler::kNoCacheBecauseV8Extension:
2374          return CacheBehaviour::kNoCacheBecauseV8Extension;
2375        case ScriptCompiler::kNoCacheBecauseExtensionModule:
2376          return CacheBehaviour::kNoCacheBecauseExtensionModule;
2377        case ScriptCompiler::kNoCacheBecausePacScript:
2378          return CacheBehaviour::kNoCacheBecausePacScript;
2379        case ScriptCompiler::kNoCacheBecauseInDocumentWrite:
2380          return CacheBehaviour::kNoCacheBecauseInDocumentWrite;
2381        case ScriptCompiler::kNoCacheBecauseResourceWithNoCacheHandler:
2382          return CacheBehaviour::kNoCacheBecauseResourceWithNoCacheHandler;
2383        case ScriptCompiler::kNoCacheBecauseDeferredProduceCodeCache: {
2384          if (hit_isolate_cache_) {
2385            return CacheBehaviour::kHitIsolateCacheWhenProduceCodeCache;
2386          } else {
2387            return CacheBehaviour::kProduceCodeCache;
2388          }
2389        }
2390      }
2391      UNREACHABLE();
2392    }
2393  
GetCacheBehaviourTimedHistogramv8::internal::__anon75b411e30611::ScriptCompileTimerScope2394    TimedHistogram* GetCacheBehaviourTimedHistogram(
2395        CacheBehaviour cache_behaviour) {
2396      switch (cache_behaviour) {
2397        case CacheBehaviour::kProduceCodeCache:
2398        // Even if we hit the isolate's compilation cache, we currently recompile
2399        // when we want to produce the code cache.
2400        case CacheBehaviour::kHitIsolateCacheWhenProduceCodeCache:
2401          return isolate_->counters()->compile_script_with_produce_cache();
2402        case CacheBehaviour::kHitIsolateCacheWhenNoCache:
2403        case CacheBehaviour::kHitIsolateCacheWhenConsumeCodeCache:
2404        case CacheBehaviour::kHitIsolateCacheWhenStreamingSource:
2405          return isolate_->counters()->compile_script_with_isolate_cache_hit();
2406        case CacheBehaviour::kConsumeCodeCacheFailed:
2407          return isolate_->counters()->compile_script_consume_failed();
2408        case CacheBehaviour::kConsumeCodeCache:
2409          return isolate_->counters()->compile_script_with_consume_cache();
2410  
2411        // Note that this only counts the finalization part of streaming, the
2412        // actual streaming compile is counted by BackgroundCompileTask into
2413        // "compile_script_on_background".
2414        case CacheBehaviour::kNoCacheBecauseStreamingSource:
2415          return isolate_->counters()->compile_script_streaming_finalization();
2416  
2417        case CacheBehaviour::kNoCacheBecauseInlineScript:
2418          return isolate_->counters()
2419              ->compile_script_no_cache_because_inline_script();
2420        case CacheBehaviour::kNoCacheBecauseScriptTooSmall:
2421          return isolate_->counters()
2422              ->compile_script_no_cache_because_script_too_small();
2423        case CacheBehaviour::kNoCacheBecauseCacheTooCold:
2424          return isolate_->counters()
2425              ->compile_script_no_cache_because_cache_too_cold();
2426  
2427        // Aggregate all the other "no cache" counters into a single histogram, to
2428        // save space.
2429        case CacheBehaviour::kNoCacheNoReason:
2430        case CacheBehaviour::kNoCacheBecauseNoResource:
2431        case CacheBehaviour::kNoCacheBecauseInspector:
2432        case CacheBehaviour::kNoCacheBecauseCachingDisabled:
2433        // TODO(leszeks): Consider counting separately once modules are more
2434        // common.
2435        case CacheBehaviour::kNoCacheBecauseModule:
2436        case CacheBehaviour::kNoCacheBecauseV8Extension:
2437        case CacheBehaviour::kNoCacheBecauseExtensionModule:
2438        case CacheBehaviour::kNoCacheBecausePacScript:
2439        case CacheBehaviour::kNoCacheBecauseInDocumentWrite:
2440        case CacheBehaviour::kNoCacheBecauseResourceWithNoCacheHandler:
2441          return isolate_->counters()->compile_script_no_cache_other();
2442  
2443        case CacheBehaviour::kCount:
2444          UNREACHABLE();
2445      }
2446      UNREACHABLE();
2447    }
2448  };
2449  
SetScriptFieldsFromDetails(Isolate * isolate,Script script,Compiler::ScriptDetails script_details,DisallowHeapAllocation * no_gc)2450  void SetScriptFieldsFromDetails(Isolate* isolate, Script script,
2451                                  Compiler::ScriptDetails script_details,
2452                                  DisallowHeapAllocation* no_gc) {
2453    Handle<Object> script_name;
2454    if (script_details.name_obj.ToHandle(&script_name)) {
2455      script.set_name(*script_name);
2456      script.set_line_offset(script_details.line_offset);
2457      script.set_column_offset(script_details.column_offset);
2458    }
2459    // The API can provide a source map URL, but a source map URL could also have
2460    // been inferred by the parser from a magic comment. The latter takes
2461    // preference over the former, so we don't want to override the source mapping
2462    // URL if it already exists.
2463    Handle<Object> source_map_url;
2464    if (script_details.source_map_url.ToHandle(&source_map_url) &&
2465        script.source_mapping_url(isolate).IsUndefined(isolate)) {
2466      script.set_source_mapping_url(*source_map_url);
2467    }
2468    Handle<FixedArray> host_defined_options;
2469    if (script_details.host_defined_options.ToHandle(&host_defined_options)) {
2470      script.set_host_defined_options(*host_defined_options);
2471    }
2472  }
2473  
NewScript(Isolate * isolate,ParseInfo * parse_info,Handle<String> source,Compiler::ScriptDetails script_details,ScriptOriginOptions origin_options,NativesFlag natives,MaybeHandle<FixedArray> maybe_wrapped_arguments=kNullMaybeHandle)2474  Handle<Script> NewScript(
2475      Isolate* isolate, ParseInfo* parse_info, Handle<String> source,
2476      Compiler::ScriptDetails script_details, ScriptOriginOptions origin_options,
2477      NativesFlag natives,
2478      MaybeHandle<FixedArray> maybe_wrapped_arguments = kNullMaybeHandle) {
2479    // Create a script object describing the script to be compiled.
2480    Handle<Script> script = parse_info->CreateScript(
2481        isolate, source, maybe_wrapped_arguments, origin_options, natives);
2482    DisallowHeapAllocation no_gc;
2483    SetScriptFieldsFromDetails(isolate, *script, script_details, &no_gc);
2484    LOG(isolate, ScriptDetails(*script));
2485    return script;
2486  }
2487  
CompileScriptOnMainThread(const UnoptimizedCompileFlags flags,Handle<String> source,const Compiler::ScriptDetails & script_details,ScriptOriginOptions origin_options,NativesFlag natives,v8::Extension * extension,Isolate * isolate,IsCompiledScope * is_compiled_scope)2488  MaybeHandle<SharedFunctionInfo> CompileScriptOnMainThread(
2489      const UnoptimizedCompileFlags flags, Handle<String> source,
2490      const Compiler::ScriptDetails& script_details,
2491      ScriptOriginOptions origin_options, NativesFlag natives,
2492      v8::Extension* extension, Isolate* isolate,
2493      IsCompiledScope* is_compiled_scope) {
2494    UnoptimizedCompileState compile_state(isolate);
2495    ParseInfo parse_info(isolate, flags, &compile_state);
2496    parse_info.set_extension(extension);
2497  
2498    Handle<Script> script = NewScript(isolate, &parse_info, source,
2499                                      script_details, origin_options, natives);
2500    DCHECK_IMPLIES(parse_info.flags().collect_type_profile(),
2501                   script->IsUserJavaScript());
2502    DCHECK_EQ(parse_info.flags().is_repl_mode(), script->is_repl_mode());
2503  
2504    return CompileToplevel(&parse_info, script, isolate, is_compiled_scope);
2505  }
2506  
2507  class StressBackgroundCompileThread : public base::Thread {
2508   public:
StressBackgroundCompileThread(Isolate * isolate,Handle<String> source)2509    StressBackgroundCompileThread(Isolate* isolate, Handle<String> source)
2510        : base::Thread(
2511              base::Thread::Options("StressBackgroundCompileThread", 2 * i::MB)),
2512          source_(source),
2513          streamed_source_(std::make_unique<SourceStream>(source, isolate),
2514                           v8::ScriptCompiler::StreamedSource::UTF8) {
2515      data()->task = std::make_unique<i::BackgroundCompileTask>(data(), isolate);
2516    }
2517  
Run()2518    void Run() override { data()->task->Run(); }
2519  
data()2520    ScriptStreamingData* data() { return streamed_source_.impl(); }
2521  
2522   private:
2523    // Dummy external source stream which returns the whole source in one go.
2524    // TODO(leszeks): Also test chunking the data.
2525    class SourceStream : public v8::ScriptCompiler::ExternalSourceStream {
2526     public:
SourceStream(Handle<String> source,Isolate * isolate)2527      SourceStream(Handle<String> source, Isolate* isolate) : done_(false) {
2528        source_buffer_ = source->ToCString(ALLOW_NULLS, FAST_STRING_TRAVERSAL,
2529                                           &source_length_);
2530      }
2531  
GetMoreData(const uint8_t ** src)2532      size_t GetMoreData(const uint8_t** src) override {
2533        if (done_) {
2534          return 0;
2535        }
2536        *src = reinterpret_cast<uint8_t*>(source_buffer_.release());
2537        done_ = true;
2538  
2539        return source_length_;
2540      }
2541  
2542     private:
2543      int source_length_;
2544      std::unique_ptr<char[]> source_buffer_;
2545      bool done_;
2546    };
2547  
2548    Handle<String> source_;
2549    v8::ScriptCompiler::StreamedSource streamed_source_;
2550  };
2551  
CanBackgroundCompile(const Compiler::ScriptDetails & script_details,ScriptOriginOptions origin_options,v8::Extension * extension,ScriptCompiler::CompileOptions compile_options,NativesFlag natives)2552  bool CanBackgroundCompile(const Compiler::ScriptDetails& script_details,
2553                            ScriptOriginOptions origin_options,
2554                            v8::Extension* extension,
2555                            ScriptCompiler::CompileOptions compile_options,
2556                            NativesFlag natives) {
2557    // TODO(leszeks): Remove the module check once background compilation of
2558    // modules is supported.
2559    return !origin_options.IsModule() && !extension &&
2560           script_details.repl_mode == REPLMode::kNo &&
2561           compile_options == ScriptCompiler::kNoCompileOptions &&
2562           natives == NOT_NATIVES_CODE;
2563  }
2564  
CompilationExceptionIsRangeError(Isolate * isolate,Handle<Object> obj)2565  bool CompilationExceptionIsRangeError(Isolate* isolate, Handle<Object> obj) {
2566    if (!obj->IsJSError(isolate)) return false;
2567    Handle<JSReceiver> js_obj = Handle<JSReceiver>::cast(obj);
2568    Handle<JSReceiver> constructor;
2569    if (!JSReceiver::GetConstructor(js_obj).ToHandle(&constructor)) {
2570      return false;
2571    }
2572    return *constructor == *isolate->range_error_function();
2573  }
2574  
CompileScriptOnBothBackgroundAndMainThread(Handle<String> source,const Compiler::ScriptDetails & script_details,ScriptOriginOptions origin_options,Isolate * isolate,IsCompiledScope * is_compiled_scope)2575  MaybeHandle<SharedFunctionInfo> CompileScriptOnBothBackgroundAndMainThread(
2576      Handle<String> source, const Compiler::ScriptDetails& script_details,
2577      ScriptOriginOptions origin_options, Isolate* isolate,
2578      IsCompiledScope* is_compiled_scope) {
2579    // Start a background thread compiling the script.
2580    StressBackgroundCompileThread background_compile_thread(isolate, source);
2581  
2582    UnoptimizedCompileFlags flags_copy =
2583        background_compile_thread.data()->task->flags();
2584  
2585    CHECK(background_compile_thread.Start());
2586    MaybeHandle<SharedFunctionInfo> main_thread_maybe_result;
2587    bool main_thread_had_stack_overflow = false;
2588    // In parallel, compile on the main thread to flush out any data races.
2589    {
2590      IsCompiledScope inner_is_compiled_scope;
2591      // The background thread should also create any relevant exceptions, so we
2592      // can ignore the main-thread created ones.
2593      // TODO(leszeks): Maybe verify that any thrown (or unthrown) exceptions are
2594      // equivalent.
2595      TryCatch ignore_try_catch(reinterpret_cast<v8::Isolate*>(isolate));
2596      flags_copy.set_script_id(Script::kTemporaryScriptId);
2597      main_thread_maybe_result = CompileScriptOnMainThread(
2598          flags_copy, source, script_details, origin_options, NOT_NATIVES_CODE,
2599          nullptr, isolate, &inner_is_compiled_scope);
2600      if (main_thread_maybe_result.is_null()) {
2601        // Assume all range errors are stack overflows.
2602        main_thread_had_stack_overflow = CompilationExceptionIsRangeError(
2603            isolate, handle(isolate->pending_exception(), isolate));
2604        isolate->clear_pending_exception();
2605      }
2606    }
2607  
2608    // Join with background thread and finalize compilation.
2609    background_compile_thread.Join();
2610    MaybeHandle<SharedFunctionInfo> maybe_result =
2611        Compiler::GetSharedFunctionInfoForStreamedScript(
2612            isolate, source, script_details, origin_options,
2613            background_compile_thread.data());
2614  
2615    // Either both compiles should succeed, or both should fail. The one exception
2616    // to this is that the main-thread compilation might stack overflow while the
2617    // background compilation doesn't, so relax the check to include this case.
2618    // TODO(leszeks): Compare the contents of the results of the two compiles.
2619    if (main_thread_had_stack_overflow) {
2620      CHECK(main_thread_maybe_result.is_null());
2621    } else {
2622      CHECK_EQ(maybe_result.is_null(), main_thread_maybe_result.is_null());
2623    }
2624  
2625    Handle<SharedFunctionInfo> result;
2626    if (maybe_result.ToHandle(&result)) {
2627      // The BackgroundCompileTask's IsCompiledScope will keep the result alive
2628      // until it dies at the end of this function, after which this new
2629      // IsCompiledScope can take over.
2630      *is_compiled_scope = result->is_compiled_scope(isolate);
2631    }
2632  
2633    return maybe_result;
2634  }
2635  
2636  }  // namespace
2637  
2638  // static
GetSharedFunctionInfoForScript(Isolate * isolate,Handle<String> source,const Compiler::ScriptDetails & script_details,ScriptOriginOptions origin_options,v8::Extension * extension,ScriptData * cached_data,ScriptCompiler::CompileOptions compile_options,ScriptCompiler::NoCacheReason no_cache_reason,NativesFlag natives)2639  MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
2640      Isolate* isolate, Handle<String> source,
2641      const Compiler::ScriptDetails& script_details,
2642      ScriptOriginOptions origin_options, v8::Extension* extension,
2643      ScriptData* cached_data, ScriptCompiler::CompileOptions compile_options,
2644      ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) {
2645    ScriptCompileTimerScope compile_timer(isolate, no_cache_reason);
2646  
2647    if (compile_options == ScriptCompiler::kNoCompileOptions ||
2648        compile_options == ScriptCompiler::kEagerCompile) {
2649      DCHECK_NULL(cached_data);
2650    } else {
2651      DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache);
2652      DCHECK(cached_data);
2653      DCHECK_NULL(extension);
2654    }
2655    int source_length = source->length();
2656    isolate->counters()->total_load_size()->Increment(source_length);
2657    isolate->counters()->total_compile_size()->Increment(source_length);
2658  
2659    LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
2660    CompilationCache* compilation_cache = isolate->compilation_cache();
2661  
2662    // For extensions or REPL mode scripts neither do a compilation cache lookup,
2663    // nor put the compilation result back into the cache.
2664    const bool use_compilation_cache =
2665        extension == nullptr && script_details.repl_mode == REPLMode::kNo;
2666    MaybeHandle<SharedFunctionInfo> maybe_result;
2667    IsCompiledScope is_compiled_scope;
2668    if (use_compilation_cache) {
2669      bool can_consume_code_cache =
2670          compile_options == ScriptCompiler::kConsumeCodeCache;
2671      if (can_consume_code_cache) {
2672        compile_timer.set_consuming_code_cache();
2673      }
2674  
2675      // First check per-isolate compilation cache.
2676      maybe_result = compilation_cache->LookupScript(
2677          source, script_details.name_obj, script_details.line_offset,
2678          script_details.column_offset, origin_options, isolate->native_context(),
2679          language_mode);
2680      if (!maybe_result.is_null()) {
2681        compile_timer.set_hit_isolate_cache();
2682      } else if (can_consume_code_cache) {
2683        compile_timer.set_consuming_code_cache();
2684        // Then check cached code provided by embedder.
2685        HistogramTimerScope timer(isolate->counters()->compile_deserialize());
2686        RuntimeCallTimerScope runtimeTimer(
2687            isolate, RuntimeCallCounterId::kCompileDeserialize);
2688        TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
2689                     "V8.CompileDeserialize");
2690        Handle<SharedFunctionInfo> inner_result;
2691        if (CodeSerializer::Deserialize(isolate, cached_data, source,
2692                                        origin_options)
2693                .ToHandle(&inner_result) &&
2694            inner_result->is_compiled()) {
2695          // Promote to per-isolate compilation cache.
2696          is_compiled_scope = inner_result->is_compiled_scope(isolate);
2697          DCHECK(is_compiled_scope.is_compiled());
2698          compilation_cache->PutScript(source, isolate->native_context(),
2699                                       language_mode, inner_result);
2700          Handle<Script> script(Script::cast(inner_result->script()), isolate);
2701          maybe_result = inner_result;
2702        } else {
2703          // Deserializer failed. Fall through to compile.
2704          compile_timer.set_consuming_code_cache_failed();
2705        }
2706      }
2707    }
2708  
2709    if (maybe_result.is_null()) {
2710      // No cache entry found compile the script.
2711      if (FLAG_stress_background_compile &&
2712          CanBackgroundCompile(script_details, origin_options, extension,
2713                               compile_options, natives)) {
2714        // If the --stress-background-compile flag is set, do the actual
2715        // compilation on a background thread, and wait for its result.
2716        maybe_result = CompileScriptOnBothBackgroundAndMainThread(
2717            source, script_details, origin_options, isolate, &is_compiled_scope);
2718      } else {
2719        UnoptimizedCompileFlags flags =
2720            UnoptimizedCompileFlags::ForToplevelCompile(
2721                isolate, natives == NOT_NATIVES_CODE, language_mode,
2722                script_details.repl_mode);
2723  
2724        flags.set_is_eager(compile_options == ScriptCompiler::kEagerCompile);
2725        flags.set_is_module(origin_options.IsModule());
2726  
2727        maybe_result = CompileScriptOnMainThread(
2728            flags, source, script_details, origin_options, natives, extension,
2729            isolate, &is_compiled_scope);
2730      }
2731  
2732      // Add the result to the isolate cache.
2733      Handle<SharedFunctionInfo> result;
2734      if (use_compilation_cache && maybe_result.ToHandle(&result)) {
2735        DCHECK(is_compiled_scope.is_compiled());
2736        compilation_cache->PutScript(source, isolate->native_context(),
2737                                     language_mode, result);
2738      } else if (maybe_result.is_null() && natives != EXTENSION_CODE) {
2739        isolate->ReportPendingMessages();
2740      }
2741    }
2742  
2743    return maybe_result;
2744  }
2745  
2746  // static
GetWrappedFunction(Handle<String> source,Handle<FixedArray> arguments,Handle<Context> context,const Compiler::ScriptDetails & script_details,ScriptOriginOptions origin_options,ScriptData * cached_data,v8::ScriptCompiler::CompileOptions compile_options,v8::ScriptCompiler::NoCacheReason no_cache_reason)2747  MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
2748      Handle<String> source, Handle<FixedArray> arguments,
2749      Handle<Context> context, const Compiler::ScriptDetails& script_details,
2750      ScriptOriginOptions origin_options, ScriptData* cached_data,
2751      v8::ScriptCompiler::CompileOptions compile_options,
2752      v8::ScriptCompiler::NoCacheReason no_cache_reason) {
2753    Isolate* isolate = context->GetIsolate();
2754    ScriptCompileTimerScope compile_timer(isolate, no_cache_reason);
2755  
2756    if (compile_options == ScriptCompiler::kNoCompileOptions ||
2757        compile_options == ScriptCompiler::kEagerCompile) {
2758      DCHECK_NULL(cached_data);
2759    } else {
2760      DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache);
2761      DCHECK(cached_data);
2762    }
2763  
2764    int source_length = source->length();
2765    isolate->counters()->total_compile_size()->Increment(source_length);
2766  
2767    LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
2768  
2769    MaybeHandle<SharedFunctionInfo> maybe_result;
2770    bool can_consume_code_cache =
2771        compile_options == ScriptCompiler::kConsumeCodeCache;
2772    if (can_consume_code_cache) {
2773      compile_timer.set_consuming_code_cache();
2774      // Then check cached code provided by embedder.
2775      HistogramTimerScope timer(isolate->counters()->compile_deserialize());
2776      RuntimeCallTimerScope runtimeTimer(
2777          isolate, RuntimeCallCounterId::kCompileDeserialize);
2778      TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
2779                   "V8.CompileDeserialize");
2780      maybe_result = CodeSerializer::Deserialize(isolate, cached_data, source,
2781                                                 origin_options);
2782      if (maybe_result.is_null()) {
2783        // Deserializer failed. Fall through to compile.
2784        compile_timer.set_consuming_code_cache_failed();
2785      }
2786    }
2787  
2788    Handle<SharedFunctionInfo> wrapped;
2789    Handle<Script> script;
2790    IsCompiledScope is_compiled_scope;
2791    if (!maybe_result.ToHandle(&wrapped)) {
2792      UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile(
2793          isolate, true, language_mode, script_details.repl_mode);
2794      flags.set_is_eval(true);  // Use an eval scope as declaration scope.
2795      flags.set_function_syntax_kind(FunctionSyntaxKind::kWrapped);
2796      // TODO(delphick): Remove this and instead make the wrapped and wrapper
2797      // functions fully non-lazy instead thus preventing source positions from
2798      // being omitted.
2799      flags.set_collect_source_positions(true);
2800      // flags.set_eager(compile_options == ScriptCompiler::kEagerCompile);
2801  
2802      UnoptimizedCompileState compile_state(isolate);
2803      ParseInfo parse_info(isolate, flags, &compile_state);
2804  
2805      MaybeHandle<ScopeInfo> maybe_outer_scope_info;
2806      if (!context->IsNativeContext()) {
2807        maybe_outer_scope_info = handle(context->scope_info(), isolate);
2808      }
2809  
2810      script = NewScript(isolate, &parse_info, source, script_details,
2811                         origin_options, NOT_NATIVES_CODE, arguments);
2812  
2813      Handle<SharedFunctionInfo> top_level;
2814      maybe_result = CompileToplevel(&parse_info, script, maybe_outer_scope_info,
2815                                     isolate, &is_compiled_scope);
2816      if (maybe_result.is_null()) isolate->ReportPendingMessages();
2817      ASSIGN_RETURN_ON_EXCEPTION(isolate, top_level, maybe_result, JSFunction);
2818  
2819      SharedFunctionInfo::ScriptIterator infos(isolate, *script);
2820      for (SharedFunctionInfo info = infos.Next(); !info.is_null();
2821           info = infos.Next()) {
2822        if (info.is_wrapped()) {
2823          wrapped = Handle<SharedFunctionInfo>(info, isolate);
2824          break;
2825        }
2826      }
2827      DCHECK(!wrapped.is_null());
2828    } else {
2829      is_compiled_scope = wrapped->is_compiled_scope(isolate);
2830      script = Handle<Script>(Script::cast(wrapped->script()), isolate);
2831    }
2832    DCHECK(is_compiled_scope.is_compiled());
2833  
2834    return isolate->factory()->NewFunctionFromSharedFunctionInfo(
2835        wrapped, context, AllocationType::kYoung);
2836  }
2837  
2838  // static
2839  MaybeHandle<SharedFunctionInfo>
GetSharedFunctionInfoForStreamedScript(Isolate * isolate,Handle<String> source,const ScriptDetails & script_details,ScriptOriginOptions origin_options,ScriptStreamingData * streaming_data)2840  Compiler::GetSharedFunctionInfoForStreamedScript(
2841      Isolate* isolate, Handle<String> source,
2842      const ScriptDetails& script_details, ScriptOriginOptions origin_options,
2843      ScriptStreamingData* streaming_data) {
2844    DCHECK(!origin_options.IsModule());
2845    DCHECK(!origin_options.IsWasm());
2846  
2847    ScriptCompileTimerScope compile_timer(
2848        isolate, ScriptCompiler::kNoCacheBecauseStreamingSource);
2849    PostponeInterruptsScope postpone(isolate);
2850  
2851    int source_length = source->length();
2852    isolate->counters()->total_load_size()->Increment(source_length);
2853    isolate->counters()->total_compile_size()->Increment(source_length);
2854  
2855    BackgroundCompileTask* task = streaming_data->task.get();
2856  
2857    MaybeHandle<SharedFunctionInfo> maybe_result;
2858    // Check if compile cache already holds the SFI, if so no need to finalize
2859    // the code compiled on the background thread.
2860    CompilationCache* compilation_cache = isolate->compilation_cache();
2861    {
2862      TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
2863                   "V8.StreamingFinalization.CheckCache");
2864      maybe_result = compilation_cache->LookupScript(
2865          source, script_details.name_obj, script_details.line_offset,
2866          script_details.column_offset, origin_options, isolate->native_context(),
2867          task->language_mode());
2868      if (!maybe_result.is_null()) {
2869        compile_timer.set_hit_isolate_cache();
2870      }
2871    }
2872  
2873    if (maybe_result.is_null()) {
2874      // No cache entry found, finalize compilation of the script and add it to
2875      // the isolate cache.
2876  
2877      Handle<Script> script;
2878      if (FLAG_finalize_streaming_on_background) {
2879        RuntimeCallTimerScope runtimeTimerScope(
2880            isolate, RuntimeCallCounterId::kCompilePublishBackgroundFinalization);
2881        TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
2882                     "V8.OffThreadFinalization.Publish");
2883  
2884        script = task->GetScript(isolate);
2885  
2886        // We might not have been able to finalize all jobs on the background
2887        // thread (e.g. asm.js jobs), so finalize those deferred jobs now.
2888        if (FinalizeDeferredUnoptimizedCompilationJobs(
2889                isolate, script,
2890                task->jobs_to_retry_finalization_on_main_thread(),
2891                task->compile_state()->pending_error_handler(),
2892                task->finalize_unoptimized_compilation_data())) {
2893          maybe_result = task->GetOuterFunctionSfi(isolate);
2894        }
2895  
2896        script->set_source(*source);
2897        script->set_origin_options(origin_options);
2898  
2899        // The one post-hoc fix-up: Add the script to the script list.
2900        Handle<WeakArrayList> scripts = isolate->factory()->script_list();
2901        scripts = WeakArrayList::Append(isolate, scripts,
2902                                        MaybeObjectHandle::Weak(script));
2903        isolate->heap()->SetRootScriptList(*scripts);
2904      } else {
2905        ParseInfo* parse_info = task->info();
2906        DCHECK(parse_info->flags().is_toplevel());
2907  
2908        script = parse_info->CreateScript(isolate, source, kNullMaybeHandle,
2909                                          origin_options);
2910  
2911        task->parser()->UpdateStatistics(isolate, script);
2912        task->parser()->HandleSourceURLComments(isolate, script);
2913  
2914        if (!task->compilation_jobs()->empty()) {
2915          // Off-thread parse & compile has succeeded - finalize compilation.
2916          DCHECK_NOT_NULL(parse_info->literal());
2917  
2918          parse_info->ast_value_factory()->Internalize(isolate);
2919  
2920          Handle<SharedFunctionInfo> shared_info =
2921              CreateTopLevelSharedFunctionInfo(parse_info, script, isolate);
2922          if (FinalizeAllUnoptimizedCompilationJobs(
2923                  parse_info, isolate, script, task->compilation_jobs(),
2924                  task->finalize_unoptimized_compilation_data())) {
2925            maybe_result = shared_info;
2926          }
2927        }
2928  
2929        if (maybe_result.is_null()) {
2930          // Compilation failed - prepare to throw an exception after script
2931          // fields have been set.
2932          PreparePendingException(isolate, parse_info);
2933        }
2934      }
2935  
2936      // Set the script fields after finalization, to keep this path the same
2937      // between main-thread and off-thread finalization.
2938      {
2939        DisallowHeapAllocation no_gc;
2940        SetScriptFieldsFromDetails(isolate, *script, script_details, &no_gc);
2941        LOG(isolate, ScriptDetails(*script));
2942      }
2943  
2944      Handle<SharedFunctionInfo> result;
2945      if (!maybe_result.ToHandle(&result)) {
2946        FailWithPreparedPendingException(
2947            isolate, script, task->compile_state()->pending_error_handler());
2948      } else {
2949        FinalizeUnoptimizedScriptCompilation(
2950            isolate, script, task->flags(), task->compile_state(),
2951            *task->finalize_unoptimized_compilation_data());
2952  
2953        // Add compiled code to the isolate cache.
2954        TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
2955                     "V8.StreamingFinalization.AddToCache");
2956        compilation_cache->PutScript(source, isolate->native_context(),
2957                                     task->language_mode(), result);
2958      }
2959    }
2960  
2961    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
2962                 "V8.StreamingFinalization.Release");
2963    streaming_data->Release();
2964    return maybe_result;
2965  }
2966  
2967  // static
2968  template <typename LocalIsolate>
GetSharedFunctionInfo(FunctionLiteral * literal,Handle<Script> script,LocalIsolate * isolate)2969  Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
2970      FunctionLiteral* literal, Handle<Script> script, LocalIsolate* isolate) {
2971    // Precondition: code has been parsed and scopes have been analyzed.
2972    MaybeHandle<SharedFunctionInfo> maybe_existing;
2973  
2974    // Find any previously allocated shared function info for the given literal.
2975    maybe_existing =
2976        script->FindSharedFunctionInfo(isolate, literal->function_literal_id());
2977  
2978    // If we found an existing shared function info, return it.
2979    Handle<SharedFunctionInfo> existing;
2980    if (maybe_existing.ToHandle(&existing)) {
2981      // If the function has been uncompiled (bytecode flushed) it will have lost
2982      // any preparsed data. If we produced preparsed data during this compile for
2983      // this function, replace the uncompiled data with one that includes it.
2984      if (literal->produced_preparse_data() != nullptr &&
2985          existing->HasUncompiledDataWithoutPreparseData()) {
2986        Handle<UncompiledData> existing_uncompiled_data =
2987            handle(existing->uncompiled_data(), isolate);
2988        DCHECK_EQ(literal->start_position(),
2989                  existing_uncompiled_data->start_position());
2990        DCHECK_EQ(literal->end_position(),
2991                  existing_uncompiled_data->end_position());
2992        // Use existing uncompiled data's inferred name as it may be more
2993        // accurate than the literal we preparsed.
2994        Handle<String> inferred_name =
2995            handle(existing_uncompiled_data->inferred_name(), isolate);
2996        Handle<PreparseData> preparse_data =
2997            literal->produced_preparse_data()->Serialize(isolate);
2998        Handle<UncompiledData> new_uncompiled_data =
2999            isolate->factory()->NewUncompiledDataWithPreparseData(
3000                inferred_name, existing_uncompiled_data->start_position(),
3001                existing_uncompiled_data->end_position(), preparse_data);
3002        existing->set_uncompiled_data(*new_uncompiled_data);
3003      }
3004      return existing;
3005    }
3006  
3007    // Allocate a shared function info object which will be compiled lazily.
3008    Handle<SharedFunctionInfo> result =
3009        isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script,
3010                                                            false);
3011    return result;
3012  }
3013  
3014  template Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
3015      FunctionLiteral* literal, Handle<Script> script, Isolate* isolate);
3016  template Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
3017      FunctionLiteral* literal, Handle<Script> script, LocalIsolate* isolate);
3018  
3019  // static
GetOptimizedCodeForOSR(Handle<JSFunction> function,BailoutId osr_offset,JavaScriptFrame * osr_frame)3020  MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function,
3021                                                     BailoutId osr_offset,
3022                                                     JavaScriptFrame* osr_frame) {
3023    DCHECK(!osr_offset.IsNone());
3024    DCHECK_NOT_NULL(osr_frame);
3025    return GetOptimizedCode(function, ConcurrencyMode::kNotConcurrent,
3026                            CodeKindForTopTier(), osr_offset, osr_frame);
3027  }
3028  
3029  // static
FinalizeOptimizedCompilationJob(OptimizedCompilationJob * job,Isolate * isolate)3030  bool Compiler::FinalizeOptimizedCompilationJob(OptimizedCompilationJob* job,
3031                                                 Isolate* isolate) {
3032    VMState<COMPILER> state(isolate);
3033    // Take ownership of the job. Deleting the job also tears down the zone.
3034    std::unique_ptr<OptimizedCompilationJob> job_scope(job);
3035    OptimizedCompilationInfo* compilation_info = job->compilation_info();
3036  
3037    TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
3038    RuntimeCallTimerScope runtimeTimer(
3039        isolate, RuntimeCallCounterId::kOptimizeConcurrentFinalize);
3040    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
3041                 "V8.OptimizeConcurrentFinalize");
3042  
3043    Handle<SharedFunctionInfo> shared = compilation_info->shared_info();
3044  
3045    CodeKind code_kind = compilation_info->code_kind();
3046    const bool should_install_code_on_function =
3047        !IsForNativeContextIndependentCachingOnly(code_kind);
3048    if (should_install_code_on_function) {
3049      // Reset profiler ticks, function is no longer considered hot.
3050      compilation_info->closure()->feedback_vector().set_profiler_ticks(0);
3051    }
3052  
3053    DCHECK(!shared->HasBreakInfo());
3054  
3055    // 1) Optimization on the concurrent thread may have failed.
3056    // 2) The function may have already been optimized by OSR.  Simply continue.
3057    //    Except when OSR already disabled optimization for some reason.
3058    // 3) The code may have already been invalidated due to dependency change.
3059    // 4) Code generation may have failed.
3060    if (job->state() == CompilationJob::State::kReadyToFinalize) {
3061      if (shared->optimization_disabled()) {
3062        job->RetryOptimization(BailoutReason::kOptimizationDisabled);
3063      } else if (job->FinalizeJob(isolate) == CompilationJob::SUCCEEDED) {
3064        job->RecordCompilationStats(OptimizedCompilationJob::kConcurrent,
3065                                    isolate);
3066        job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG,
3067                                       isolate);
3068        InsertCodeIntoOptimizedCodeCache(compilation_info);
3069        InsertCodeIntoCompilationCache(isolate, compilation_info);
3070        CompilerTracer::TraceCompletedJob(isolate, compilation_info);
3071        if (should_install_code_on_function) {
3072          compilation_info->closure()->set_code(*compilation_info->code());
3073        }
3074        return CompilationJob::SUCCEEDED;
3075      }
3076    }
3077  
3078    DCHECK_EQ(job->state(), CompilationJob::State::kFailed);
3079    CompilerTracer::TraceAbortedJob(isolate, compilation_info);
3080    compilation_info->closure()->set_code(shared->GetCode());
3081    // Clear the InOptimizationQueue marker, if it exists.
3082    if (UsesOptimizationMarker(code_kind) &&
3083        compilation_info->closure()->IsInOptimizationQueue()) {
3084      compilation_info->closure()->ClearOptimizationMarker();
3085    }
3086    return CompilationJob::FAILED;
3087  }
3088  
3089  // static
PostInstantiation(Handle<JSFunction> function)3090  void Compiler::PostInstantiation(Handle<JSFunction> function) {
3091    Isolate* isolate = function->GetIsolate();
3092    Handle<SharedFunctionInfo> shared(function->shared(), isolate);
3093    IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
3094  
3095    // If code is compiled to bytecode (i.e., isn't asm.js), then allocate a
3096    // feedback and check for optimized code.
3097    if (is_compiled_scope.is_compiled() && shared->HasBytecodeArray()) {
3098      JSFunction::InitializeFeedbackCell(function, &is_compiled_scope);
3099  
3100      Code code = function->has_feedback_vector()
3101                      ? function->feedback_vector().optimized_code()
3102                      : Code();
3103      if (!code.is_null()) {
3104        // Caching of optimized code enabled and optimized code found.
3105        DCHECK(!code.marked_for_deoptimization());
3106        DCHECK(function->shared().is_compiled());
3107        function->set_code(code);
3108      }
3109  
3110      if (FLAG_always_opt && shared->allows_lazy_compilation() &&
3111          !shared->optimization_disabled() &&
3112          !function->HasAvailableOptimizedCode()) {
3113        CompilerTracer::TraceMarkForAlwaysOpt(isolate, function);
3114        JSFunction::EnsureFeedbackVector(function, &is_compiled_scope);
3115        function->MarkForOptimization(ConcurrencyMode::kNotConcurrent);
3116      }
3117    }
3118  
3119    if (shared->is_toplevel() || shared->is_wrapped()) {
3120      // If it's a top-level script, report compilation to the debugger.
3121      Handle<Script> script(Script::cast(shared->script()), isolate);
3122      isolate->debug()->OnAfterCompile(script);
3123    }
3124  }
3125  
3126  // ----------------------------------------------------------------------------
3127  // Implementation of ScriptStreamingData
3128  
ScriptStreamingData(std::unique_ptr<ScriptCompiler::ExternalSourceStream> source_stream,ScriptCompiler::StreamedSource::Encoding encoding)3129  ScriptStreamingData::ScriptStreamingData(
3130      std::unique_ptr<ScriptCompiler::ExternalSourceStream> source_stream,
3131      ScriptCompiler::StreamedSource::Encoding encoding)
3132      : source_stream(std::move(source_stream)), encoding(encoding) {}
3133  
3134  ScriptStreamingData::~ScriptStreamingData() = default;
3135  
Release()3136  void ScriptStreamingData::Release() { task.reset(); }
3137  
3138  }  // namespace internal
3139  }  // namespace v8
3140