xref: /third_party/node/deps/v8/src/codegen/compiler.cc (revision 1cb0ef41)
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
72namespace v8 {
73namespace internal {
74
75namespace {
76
77constexpr bool IsOSR(BytecodeOffset osr_offset) { return !osr_offset.IsNone(); }
78
79void 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
88void ResetTieringState(JSFunction function, BytecodeOffset osr_offset) {
89  if (function.has_feedback_vector()) {
90    SetTieringState(function, osr_offset, TieringState::kNone);
91  }
92}
93
94void 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
102class CompilerTracer : public AllStatic {
103 public:
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
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
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
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
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
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
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
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
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
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
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:
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
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
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
242  static void PrintTraceSuffix(const CodeTracer::Scope& scope) {
243    PrintF(scope.file(), "]\n");
244  }
245};
246
247void 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.
324struct ScopedTimer {
325  explicit ScopedTimer(base::TimeDelta* location) : location_(location) {
326    DCHECK_NOT_NULL(location_);
327    timer_.Start();
328  }
329
330  ~ScopedTimer() { *location_ += timer_.Elapsed(); }
331
332  base::ElapsedTimer timer_;
333  base::TimeDelta* location_;
334};
335
336namespace {
337
338ScriptOriginOptions 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
360CompilationJob::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
367CompilationJob::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
379CompilationJob::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
387namespace {
388
389void 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
410void 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
442CompilationJob::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
452CompilationJob::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
462CompilationJob::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
472CompilationJob::Status TurbofanCompilationJob::RetryOptimization(
473    BailoutReason reason) {
474  DCHECK(compilation_info_->IsOptimizing());
475  compilation_info_->RetryOptimization(reason);
476  return UpdateState(FAILED, State::kFailed);
477}
478
479CompilationJob::Status TurbofanCompilationJob::AbortOptimization(
480    BailoutReason reason) {
481  DCHECK(compilation_info_->IsOptimizing());
482  compilation_info_->AbortOptimization(reason);
483  return UpdateState(FAILED, State::kFailed);
484}
485
486void 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
556void 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
577namespace {
578
579#if V8_ENABLE_WEBASSEMBLY
580bool 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
596void 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
633template <typename IsolateT>
634void 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
669void 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
680template <typename IsolateT>
681void 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
697void 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.
720template <typename IsolateT>
721CompilationJob::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
747std::unique_ptr<UnoptimizedCompilationJob>
748ExecuteSingleUnoptimizedCompilationJob(
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
780template <typename IsolateT>
781bool 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
861bool 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.
895class OptimizedCodeCache : public AllStatic {
896 public:
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
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.
972bool 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
982bool 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
1021bool 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
1070enum 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
1077bool 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
1090MaybeHandle<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.
1133void 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
1150MaybeHandle<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
1213MaybeHandle<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.
1274void 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
1293bool FailAndClearPendingException(Isolate* isolate) {
1294  isolate->clear_pending_exception();
1295  return false;
1296}
1297
1298template <typename IsolateT>
1299bool 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
1307bool 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
1325bool 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
1333void 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
1381void 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
1397void 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.
1413template <typename IsolateT>
1414Handle<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
1423MaybeHandle<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
1486RuntimeCallCounterId 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
1499CompilationHandleScope::~CompilationHandleScope() {
1500  info_->set_persistent_handles(persistent_.Detach());
1501}
1502
1503FinalizeUnoptimizedCompilationData::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
1514DeferredFinalizationJobData::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
1520BackgroundCompileTask::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
1541BackgroundCompileTask::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
1569BackgroundCompileTask::~BackgroundCompileTask() = default;
1570
1571namespace {
1572
1573void 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
1602void 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
1613void 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
1619void 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
1729MaybeHandle<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
1781bool 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
1822void 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
1830void 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
1841BackgroundDeserializeTask::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
1854void 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
1864MaybeHandle<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
1876bool 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
1979bool 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
2060bool 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
2135bool 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
2187bool 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
2206bool 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
2232MaybeHandle<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
2240bool 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
2257void 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
2287MaybeHandle<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
2295MaybeHandle<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)
2435bool 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)
2451bool 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
2492std::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
2554MaybeHandle<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
2582MaybeHandle<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
2593namespace {
2594
2595struct 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
2795Handle<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
2809MaybeHandle<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
2829class 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
2876bool 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
2888bool 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
2898MaybeHandle<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
2964MaybeHandle<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
3105MaybeHandle<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
3115MaybeHandle<SharedFunctionInfo>
3116Compiler::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
3125MaybeHandle<SharedFunctionInfo>
3126Compiler::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
3136MaybeHandle<SharedFunctionInfo>
3137Compiler::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
3149MaybeHandle<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
3244MaybeHandle<SharedFunctionInfo>
3245Compiler::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
3301Handle<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
3325template <typename IsolateT>
3326Handle<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
3370template Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
3371    FunctionLiteral* literal, Handle<Script> script, Isolate* isolate);
3372template Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
3373    FunctionLiteral* literal, Handle<Script> script, LocalIsolate* isolate);
3374
3375// static
3376MaybeHandle<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
3424void 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
3434bool 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
3499bool 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
3509void 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
3562ScriptStreamingData::ScriptStreamingData(
3563    std::unique_ptr<ScriptCompiler::ExternalSourceStream> source_stream,
3564    ScriptCompiler::StreamedSource::Encoding encoding)
3565    : source_stream(std::move(source_stream)), encoding(encoding) {}
3566
3567ScriptStreamingData::~ScriptStreamingData() = default;
3568
3569void ScriptStreamingData::Release() { task.reset(); }
3570
3571}  // namespace internal
3572}  // namespace v8
3573