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