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