V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
compiler.cc
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/compiler.h"
6 
7 #include <algorithm>
8 #include <memory>
9 
10 #include "src/api-inl.h"
11 #include "src/asmjs/asm-js.h"
12 #include "src/assembler-inl.h"
13 #include "src/ast/prettyprinter.h"
14 #include "src/ast/scopes.h"
15 #include "src/base/optional.h"
16 #include "src/bootstrapper.h"
17 #include "src/compilation-cache.h"
18 #include "src/compiler-dispatcher/compiler-dispatcher.h"
19 #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
20 #include "src/compiler/pipeline.h"
21 #include "src/debug/debug.h"
22 #include "src/debug/liveedit.h"
23 #include "src/frames-inl.h"
24 #include "src/globals.h"
25 #include "src/heap/heap.h"
26 #include "src/interpreter/interpreter.h"
27 #include "src/isolate-inl.h"
28 #include "src/log-inl.h"
29 #include "src/message-template.h"
30 #include "src/objects/map.h"
31 #include "src/optimized-compilation-info.h"
32 #include "src/parsing/parse-info.h"
33 #include "src/parsing/parser.h"
34 #include "src/parsing/parsing.h"
35 #include "src/parsing/rewriter.h"
36 #include "src/parsing/scanner-character-streams.h"
37 #include "src/runtime-profiler.h"
38 #include "src/snapshot/code-serializer.h"
39 #include "src/unoptimized-compilation-info.h"
40 #include "src/vm-state-inl.h"
41 
42 namespace v8 {
43 namespace internal {
44 
45 // A wrapper around a OptimizedCompilationInfo that detaches the Handles from
46 // the underlying DeferredHandleScope and stores them in info_ on
47 // destruction.
49  public:
50  explicit CompilationHandleScope(Isolate* isolate,
52  : deferred_(isolate), info_(info) {}
53  ~CompilationHandleScope() { info_->set_deferred_handles(deferred_.Detach()); }
54 
55  private:
56  DeferredHandleScope deferred_;
58 };
59 
60 // Helper that times a scoped region and records the elapsed time.
61 struct ScopedTimer {
62  explicit ScopedTimer(base::TimeDelta* location) : location_(location) {
63  DCHECK_NOT_NULL(location_);
64  timer_.Start();
65  }
66 
67  ~ScopedTimer() { *location_ += timer_.Elapsed(); }
68 
69  base::ElapsedTimer timer_;
70  base::TimeDelta* location_;
71 };
72 
73 namespace {
74 
75 void LogFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
77  Handle<Script> script,
78  Handle<AbstractCode> abstract_code, bool optimizing,
79  double time_taken_ms, Isolate* isolate) {
80  DCHECK(!abstract_code.is_null());
81  DCHECK(!abstract_code.is_identical_to(BUILTIN_CODE(isolate, CompileLazy)));
82 
83  // Log the code generation. If source information is available include
84  // script name and line number. Check explicitly whether logging is
85  // enabled as finding the line number is not free.
86  if (!isolate->logger()->is_listening_to_code_events() &&
87  !isolate->is_profiling() && !FLAG_log_function_events &&
88  !isolate->code_event_dispatcher()->IsListeningToCodeEvents()) {
89  return;
90  }
91 
92  int line_num = Script::GetLineNumber(script, shared->StartPosition()) + 1;
93  int column_num = Script::GetColumnNumber(script, shared->StartPosition()) + 1;
94  String script_name = script->name()->IsString()
95  ? String::cast(script->name())
96  : ReadOnlyRoots(isolate).empty_string();
97  CodeEventListener::LogEventsAndTags log_tag =
98  Logger::ToNativeByScript(tag, *script);
99  PROFILE(isolate, CodeCreateEvent(log_tag, *abstract_code, *shared,
100  script_name, line_num, column_num));
101  if (!FLAG_log_function_events) return;
102 
103  DisallowHeapAllocation no_gc;
104 
105  std::string name = optimizing ? "optimize" : "compile";
106  switch (tag) {
107  case CodeEventListener::EVAL_TAG:
108  name += "-eval";
109  break;
110  case CodeEventListener::SCRIPT_TAG:
111  break;
112  case CodeEventListener::LAZY_COMPILE_TAG:
113  name += "-lazy";
114  break;
115  case CodeEventListener::FUNCTION_TAG:
116  break;
117  default:
118  UNREACHABLE();
119  }
120 
121  LOG(isolate, FunctionEvent(name.c_str(), script->id(), time_taken_ms,
122  shared->StartPosition(), shared->EndPosition(),
123  shared->DebugName()));
124 }
125 
126 ScriptOriginOptions OriginOptionsForEval(Object* script) {
127  if (!script->IsScript()) return ScriptOriginOptions();
128 
129  const auto outer_origin_options = Script::cast(script)->origin_options();
130  return ScriptOriginOptions(outer_origin_options.IsSharedCrossOrigin(),
131  outer_origin_options.IsOpaque());
132 }
133 
134 } // namespace
135 
136 // ----------------------------------------------------------------------------
137 // Implementation of UnoptimizedCompilationJob
138 
139 CompilationJob::Status UnoptimizedCompilationJob::ExecuteJob() {
140  DisallowHeapAccess no_heap_access;
141  // Delegate to the underlying implementation.
142  DCHECK_EQ(state(), State::kReadyToExecute);
143  ScopedTimer t(&time_taken_to_execute_);
144  return UpdateState(ExecuteJobImpl(), State::kReadyToFinalize);
145 }
146 
147 CompilationJob::Status UnoptimizedCompilationJob::FinalizeJob(
148  Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
149  DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
150  DisallowCodeDependencyChange no_dependency_change;
151  DisallowJavascriptExecution no_js(isolate);
152 
153  // Delegate to the underlying implementation.
154  DCHECK_EQ(state(), State::kReadyToFinalize);
155  ScopedTimer t(&time_taken_to_finalize_);
156  return UpdateState(FinalizeJobImpl(shared_info, isolate), State::kSucceeded);
157 }
158 
159 void UnoptimizedCompilationJob::RecordCompilationStats(Isolate* isolate) const {
160  int code_size;
161  if (compilation_info()->has_bytecode_array()) {
162  code_size = compilation_info()->bytecode_array()->SizeIncludingMetadata();
163  } else {
164  DCHECK(compilation_info()->has_asm_wasm_data());
165  code_size = compilation_info()->asm_wasm_data()->Size();
166  }
167 
168  Counters* counters = isolate->counters();
169  // TODO(4280): Rename counters from "baseline" to "unoptimized" eventually.
170  counters->total_baseline_code_size()->Increment(code_size);
171  counters->total_baseline_compile_count()->Increment(1);
172 
173  // TODO(5203): Add timers for each phase of compilation.
174 }
175 
176 void UnoptimizedCompilationJob::RecordFunctionCompilation(
177  CodeEventListener::LogEventsAndTags tag, Handle<SharedFunctionInfo> shared,
178  Isolate* isolate) const {
179  Handle<AbstractCode> abstract_code;
180  if (compilation_info()->has_bytecode_array()) {
181  abstract_code =
182  Handle<AbstractCode>::cast(compilation_info()->bytecode_array());
183  } else {
184  DCHECK(compilation_info()->has_asm_wasm_data());
185  abstract_code =
186  Handle<AbstractCode>::cast(BUILTIN_CODE(isolate, InstantiateAsmJs));
187  }
188 
189  double time_taken_ms = time_taken_to_execute_.InMillisecondsF() +
190  time_taken_to_finalize_.InMillisecondsF();
191 
192  LogFunctionCompilation(tag, shared, parse_info()->script(), abstract_code,
193  false, time_taken_ms, isolate);
194 }
195 
196 // ----------------------------------------------------------------------------
197 // Implementation of OptimizedCompilationJob
198 
199 CompilationJob::Status OptimizedCompilationJob::PrepareJob(Isolate* isolate) {
200  DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
201  DisallowJavascriptExecution no_js(isolate);
202 
203  if (FLAG_trace_opt && compilation_info()->IsOptimizing()) {
204  StdoutStream os;
205  os << "[compiling method " << Brief(*compilation_info()->closure())
206  << " using " << compiler_name_;
207  if (compilation_info()->is_osr()) os << " OSR";
208  os << "]" << std::endl;
209  }
210 
211  // Delegate to the underlying implementation.
212  DCHECK_EQ(state(), State::kReadyToPrepare);
213  ScopedTimer t(&time_taken_to_prepare_);
214  return UpdateState(PrepareJobImpl(isolate), State::kReadyToExecute);
215 }
216 
217 CompilationJob::Status OptimizedCompilationJob::ExecuteJob() {
218  DisallowHeapAccess no_heap_access;
219  // Delegate to the underlying implementation.
220  DCHECK_EQ(state(), State::kReadyToExecute);
221  ScopedTimer t(&time_taken_to_execute_);
222  return UpdateState(ExecuteJobImpl(), State::kReadyToFinalize);
223 }
224 
225 CompilationJob::Status OptimizedCompilationJob::FinalizeJob(Isolate* isolate) {
226  DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
227  DisallowJavascriptExecution no_js(isolate);
228 
229  // Delegate to the underlying implementation.
230  DCHECK_EQ(state(), State::kReadyToFinalize);
231  ScopedTimer t(&time_taken_to_finalize_);
232  return UpdateState(FinalizeJobImpl(isolate), State::kSucceeded);
233 }
234 
235 CompilationJob::Status OptimizedCompilationJob::RetryOptimization(
236  BailoutReason reason) {
237  DCHECK(compilation_info_->IsOptimizing());
238  compilation_info_->RetryOptimization(reason);
239  return UpdateState(FAILED, State::kFailed);
240 }
241 
242 CompilationJob::Status OptimizedCompilationJob::AbortOptimization(
243  BailoutReason reason) {
244  DCHECK(compilation_info_->IsOptimizing());
245  compilation_info_->AbortOptimization(reason);
246  return UpdateState(FAILED, State::kFailed);
247 }
248 
249 void OptimizedCompilationJob::RecordCompilationStats() const {
250  DCHECK(compilation_info()->IsOptimizing());
251  Handle<JSFunction> function = compilation_info()->closure();
252  double ms_creategraph = time_taken_to_prepare_.InMillisecondsF();
253  double ms_optimize = time_taken_to_execute_.InMillisecondsF();
254  double ms_codegen = time_taken_to_finalize_.InMillisecondsF();
255  if (FLAG_trace_opt) {
256  PrintF("[optimizing ");
257  function->ShortPrint();
258  PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize,
259  ms_codegen);
260  }
261  if (FLAG_trace_opt_stats) {
262  static double compilation_time = 0.0;
263  static int compiled_functions = 0;
264  static int code_size = 0;
265 
266  compilation_time += (ms_creategraph + ms_optimize + ms_codegen);
267  compiled_functions++;
268  code_size += function->shared()->SourceSize();
269  PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
270  compiled_functions, code_size, compilation_time);
271  }
272 }
273 
274 void OptimizedCompilationJob::RecordFunctionCompilation(
275  CodeEventListener::LogEventsAndTags tag, Isolate* isolate) const {
276  Handle<AbstractCode> abstract_code =
277  Handle<AbstractCode>::cast(compilation_info()->code());
278 
279  double time_taken_ms = time_taken_to_prepare_.InMillisecondsF() +
280  time_taken_to_execute_.InMillisecondsF() +
281  time_taken_to_finalize_.InMillisecondsF();
282 
283  Handle<Script> script(
284  Script::cast(compilation_info()->shared_info()->script()), isolate);
285  LogFunctionCompilation(tag, compilation_info()->shared_info(), script,
286  abstract_code, true, time_taken_ms, isolate);
287 }
288 
289 // ----------------------------------------------------------------------------
290 // Local helper methods that make up the compilation pipeline.
291 
292 namespace {
293 
294 bool UseAsmWasm(FunctionLiteral* literal, bool asm_wasm_broken) {
295  // Check whether asm.js validation is enabled.
296  if (!FLAG_validate_asm) return false;
297 
298  // Modules that have validated successfully, but were subsequently broken by
299  // invalid module instantiation attempts are off limit forever.
300  if (asm_wasm_broken) return false;
301 
302  // In stress mode we want to run the validator on everything.
303  if (FLAG_stress_validate_asm) return true;
304 
305  // In general, we respect the "use asm" directive.
306  return literal->scope()->IsAsmModule();
307 }
308 
309 void InstallBytecodeArray(Handle<BytecodeArray> bytecode_array,
310  Handle<SharedFunctionInfo> shared_info,
311  ParseInfo* parse_info, Isolate* isolate) {
312  if (!FLAG_interpreted_frames_native_stack) {
313  shared_info->set_bytecode_array(*bytecode_array);
314  return;
315  }
316 
317  Handle<Code> code = isolate->factory()->CopyCode(Handle<Code>::cast(
318  isolate->factory()->interpreter_entry_trampoline_for_profiling()));
319 
320  Handle<InterpreterData> interpreter_data = Handle<InterpreterData>::cast(
321  isolate->factory()->NewStruct(INTERPRETER_DATA_TYPE, TENURED));
322 
323  interpreter_data->set_bytecode_array(*bytecode_array);
324  interpreter_data->set_interpreter_trampoline(*code);
325 
326  shared_info->set_interpreter_data(*interpreter_data);
327 
328  Handle<Script> script = parse_info->script();
329  Handle<AbstractCode> abstract_code = Handle<AbstractCode>::cast(code);
330  int line_num =
331  Script::GetLineNumber(script, shared_info->StartPosition()) + 1;
332  int column_num =
333  Script::GetColumnNumber(script, shared_info->StartPosition()) + 1;
334  String script_name = script->name()->IsString()
335  ? String::cast(script->name())
336  : ReadOnlyRoots(isolate).empty_string();
337  CodeEventListener::LogEventsAndTags log_tag = Logger::ToNativeByScript(
338  CodeEventListener::INTERPRETED_FUNCTION_TAG, *script);
339  PROFILE(isolate, CodeCreateEvent(log_tag, *abstract_code, *shared_info,
340  script_name, line_num, column_num));
341 }
342 
343 void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
344  Handle<SharedFunctionInfo> shared_info,
345  ParseInfo* parse_info, Isolate* isolate) {
346  DCHECK_EQ(shared_info->language_mode(),
347  compilation_info->literal()->language_mode());
348 
349  // Update the shared function info with the scope info.
350  Handle<ScopeInfo> scope_info = compilation_info->scope()->scope_info();
351  shared_info->set_scope_info(*scope_info);
352 
353  if (compilation_info->has_bytecode_array()) {
354  DCHECK(!shared_info->HasBytecodeArray()); // Only compiled once.
355  DCHECK(!compilation_info->has_asm_wasm_data());
356  DCHECK(!shared_info->HasFeedbackMetadata());
357 
358  Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(
359  isolate, compilation_info->feedback_vector_spec());
360 
361  InstallBytecodeArray(compilation_info->bytecode_array(), shared_info,
362  parse_info, isolate);
363  shared_info->set_feedback_metadata(*feedback_metadata);
364  } else {
365  DCHECK(compilation_info->has_asm_wasm_data());
366  shared_info->set_asm_wasm_data(*compilation_info->asm_wasm_data());
367  shared_info->set_feedback_metadata(
368  ReadOnlyRoots(isolate).empty_feedback_metadata());
369  }
370 
371  // Install coverage info on the shared function info.
372  if (compilation_info->has_coverage_info()) {
373  DCHECK(isolate->is_block_code_coverage());
374  isolate->debug()->InstallCoverageInfo(shared_info,
375  compilation_info->coverage_info());
376  }
377 }
378 
379 void EnsureSharedFunctionInfosArrayOnScript(ParseInfo* parse_info,
380  Isolate* isolate) {
381  DCHECK(parse_info->is_toplevel());
382  DCHECK(!parse_info->script().is_null());
383  if (parse_info->script()->shared_function_infos()->length() > 0) {
384  DCHECK_EQ(parse_info->script()->shared_function_infos()->length(),
385  parse_info->max_function_literal_id() + 1);
386  return;
387  }
388  Handle<WeakFixedArray> infos(isolate->factory()->NewWeakFixedArray(
389  parse_info->max_function_literal_id() + 1));
390  parse_info->script()->set_shared_function_infos(*infos);
391 }
392 
393 void SetSharedFunctionFlagsFromLiteral(FunctionLiteral* literal,
394  Handle<SharedFunctionInfo> shared_info) {
395  // Don't overwrite values set by the bootstrapper.
396  if (!shared_info->HasLength()) {
397  shared_info->set_length(literal->function_length());
398  }
399  shared_info->set_has_duplicate_parameters(
400  literal->has_duplicate_parameters());
401  shared_info->SetExpectedNofPropertiesFromEstimate(literal);
402  if (literal->dont_optimize_reason() != BailoutReason::kNoReason) {
403  shared_info->DisableOptimization(literal->dont_optimize_reason());
404  }
405 }
406 
407 CompilationJob::Status FinalizeUnoptimizedCompilationJob(
408  UnoptimizedCompilationJob* job, Handle<SharedFunctionInfo> shared_info,
409  Isolate* isolate) {
410  UnoptimizedCompilationInfo* compilation_info = job->compilation_info();
411  ParseInfo* parse_info = job->parse_info();
412 
413  SetSharedFunctionFlagsFromLiteral(compilation_info->literal(), shared_info);
414 
415  CompilationJob::Status status = job->FinalizeJob(shared_info, isolate);
416  if (status == CompilationJob::SUCCEEDED) {
417  InstallUnoptimizedCode(compilation_info, shared_info, parse_info, isolate);
418  CodeEventListener::LogEventsAndTags log_tag;
419  if (parse_info->is_toplevel()) {
420  log_tag = compilation_info->is_eval() ? CodeEventListener::EVAL_TAG
421  : CodeEventListener::SCRIPT_TAG;
422  } else {
423  log_tag = parse_info->lazy_compile() ? CodeEventListener::LAZY_COMPILE_TAG
424  : CodeEventListener::FUNCTION_TAG;
425  }
426  job->RecordFunctionCompilation(log_tag, shared_info, isolate);
427  job->RecordCompilationStats(isolate);
428  }
429  return status;
430 }
431 
432 std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs(
433  ParseInfo* parse_info, FunctionLiteral* literal,
434  AccountingAllocator* allocator,
435  UnoptimizedCompilationJobList* inner_function_jobs) {
436  if (UseAsmWasm(literal, parse_info->is_asm_wasm_broken())) {
437  std::unique_ptr<UnoptimizedCompilationJob> asm_job(
438  AsmJs::NewCompilationJob(parse_info, literal, allocator));
439  if (asm_job->ExecuteJob() == CompilationJob::SUCCEEDED) {
440  return asm_job;
441  }
442  // asm.js validation failed, fall through to standard unoptimized compile.
443  // Note: we rely on the fact that AsmJs jobs have done all validation in the
444  // PrepareJob and ExecuteJob phases and can't fail in FinalizeJob with
445  // with a validation error or another error that could be solve by falling
446  // through to standard unoptimized compile.
447  }
448  std::vector<FunctionLiteral*> eager_inner_literals;
449  std::unique_ptr<UnoptimizedCompilationJob> job(
450  interpreter::Interpreter::NewCompilationJob(
451  parse_info, literal, allocator, &eager_inner_literals));
452 
453  if (job->ExecuteJob() != CompilationJob::SUCCEEDED) {
454  // Compilation failed, return null.
455  return std::unique_ptr<UnoptimizedCompilationJob>();
456  }
457 
458  // Recursively compile eager inner literals.
459  for (FunctionLiteral* inner_literal : eager_inner_literals) {
460  std::unique_ptr<UnoptimizedCompilationJob> inner_job(
461  ExecuteUnoptimizedCompileJobs(parse_info, inner_literal, allocator,
462  inner_function_jobs));
463  // Compilation failed, return null.
464  if (!inner_job) return std::unique_ptr<UnoptimizedCompilationJob>();
465  inner_function_jobs->emplace_front(std::move(inner_job));
466  }
467 
468  return job;
469 }
470 
471 std::unique_ptr<UnoptimizedCompilationJob> GenerateUnoptimizedCode(
472  ParseInfo* parse_info, AccountingAllocator* allocator,
473  UnoptimizedCompilationJobList* inner_function_jobs) {
474  DisallowHeapAccess no_heap_access;
475  DCHECK(inner_function_jobs->empty());
476 
477  if (!Compiler::Analyze(parse_info)) {
478  return std::unique_ptr<UnoptimizedCompilationJob>();
479  }
480 
481  // Prepare and execute compilation of the outer-most function.
482  std::unique_ptr<UnoptimizedCompilationJob> outer_function_job(
483  ExecuteUnoptimizedCompileJobs(parse_info, parse_info->literal(),
484  allocator, inner_function_jobs));
485  if (!outer_function_job) return std::unique_ptr<UnoptimizedCompilationJob>();
486 
487  // Character stream shouldn't be used again.
488  parse_info->ResetCharacterStream();
489 
490  return outer_function_job;
491 }
492 
493 MaybeHandle<SharedFunctionInfo> GenerateUnoptimizedCodeForToplevel(
494  Isolate* isolate, ParseInfo* parse_info, AccountingAllocator* allocator) {
495  EnsureSharedFunctionInfosArrayOnScript(parse_info, isolate);
496  parse_info->ast_value_factory()->Internalize(isolate);
497 
498  if (!Compiler::Analyze(parse_info)) return MaybeHandle<SharedFunctionInfo>();
499  DeclarationScope::AllocateScopeInfos(parse_info, isolate);
500 
501  // Prepare and execute compilation of the outer-most function.
502  // Create the SharedFunctionInfo and add it to the script's list.
503  Handle<Script> script = parse_info->script();
504  Handle<SharedFunctionInfo> top_level =
505  isolate->factory()->NewSharedFunctionInfoForLiteral(parse_info->literal(),
506  script, true);
507 
508  std::vector<FunctionLiteral*> functions_to_compile;
509  functions_to_compile.push_back(parse_info->literal());
510 
511  while (!functions_to_compile.empty()) {
512  FunctionLiteral* literal = functions_to_compile.back();
513  functions_to_compile.pop_back();
514  Handle<SharedFunctionInfo> shared_info =
515  Compiler::GetSharedFunctionInfo(literal, script, isolate);
516  // TODO(rmcilroy): Fix this and DCHECK !is_compiled() once Full-Codegen dies
517  if (shared_info->is_compiled()) continue;
518  if (UseAsmWasm(literal, parse_info->is_asm_wasm_broken())) {
519  std::unique_ptr<UnoptimizedCompilationJob> asm_job(
520  AsmJs::NewCompilationJob(parse_info, literal, allocator));
521  if (asm_job->ExecuteJob() == CompilationJob::SUCCEEDED &&
522  FinalizeUnoptimizedCompilationJob(asm_job.get(), shared_info,
523  isolate) ==
524  CompilationJob::SUCCEEDED) {
525  continue;
526  }
527  // asm.js validation failed, fall through to standard unoptimized compile.
528  // Note: we rely on the fact that AsmJs jobs have done all validation in
529  // the PrepareJob and ExecuteJob phases and can't fail in FinalizeJob with
530  // with a validation error or another error that could be solve by falling
531  // through to standard unoptimized compile.
532  }
533 
534  std::unique_ptr<UnoptimizedCompilationJob> job(
535  interpreter::Interpreter::NewCompilationJob(
536  parse_info, literal, allocator, &functions_to_compile));
537 
538  if (job->ExecuteJob() == CompilationJob::FAILED ||
539  FinalizeUnoptimizedCompilationJob(job.get(), shared_info, isolate) ==
540  CompilationJob::FAILED) {
541  return MaybeHandle<SharedFunctionInfo>();
542  }
543  }
544 
545  // Character stream shouldn't be used again.
546  parse_info->ResetCharacterStream();
547 
548  return top_level;
549 }
550 
551 bool FinalizeUnoptimizedCode(
552  ParseInfo* parse_info, Isolate* isolate,
553  Handle<SharedFunctionInfo> shared_info,
554  UnoptimizedCompilationJob* outer_function_job,
555  UnoptimizedCompilationJobList* inner_function_jobs) {
556  DCHECK(AllowCompilation::IsAllowed(isolate));
557 
558  // TODO(rmcilroy): Clear native context in debug once AsmJS generates doesn't
559  // rely on accessing native context during finalization.
560 
561  // Allocate scope infos for the literal.
562  DeclarationScope::AllocateScopeInfos(parse_info, isolate);
563 
564  // Finalize the outer-most function's compilation job.
565  if (FinalizeUnoptimizedCompilationJob(outer_function_job, shared_info,
566  isolate) != CompilationJob::SUCCEEDED) {
567  return false;
568  }
569 
570  // Finalize the inner functions' compilation jobs.
571  for (auto&& inner_job : *inner_function_jobs) {
572  Handle<SharedFunctionInfo> inner_shared_info =
573  Compiler::GetSharedFunctionInfo(
574  inner_job->compilation_info()->literal(), parse_info->script(),
575  isolate);
576  // The inner function might be compiled already if compiling for debug.
577  // TODO(rmcilroy): Fix this and DCHECK !is_compiled() once Full-Codegen dies
578  if (inner_shared_info->is_compiled()) continue;
579  if (FinalizeUnoptimizedCompilationJob(inner_job.get(), inner_shared_info,
580  isolate) !=
581  CompilationJob::SUCCEEDED) {
582  return false;
583  }
584  }
585 
586  // Report any warnings generated during compilation.
587  if (parse_info->pending_error_handler()->has_pending_warnings()) {
588  parse_info->pending_error_handler()->ReportWarnings(isolate,
589  parse_info->script());
590  }
591 
592  return true;
593 }
594 
595 V8_WARN_UNUSED_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeCache(
596  Handle<JSFunction> function, BailoutId osr_offset) {
597  RuntimeCallTimerScope runtimeTimer(
598  function->GetIsolate(),
599  RuntimeCallCounterId::kCompileGetFromOptimizedCodeMap);
600  Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate());
601  DisallowHeapAllocation no_gc;
602  if (osr_offset.IsNone()) {
603  if (function->feedback_cell()->value()->IsFeedbackVector()) {
604  FeedbackVector* feedback_vector = function->feedback_vector();
605  feedback_vector->EvictOptimizedCodeMarkedForDeoptimization(
606  function->shared(), "GetCodeFromOptimizedCodeCache");
607  Code code = feedback_vector->optimized_code();
608 
609  if (!code.is_null()) {
610  // Caching of optimized code enabled and optimized code found.
611  DCHECK(!code->marked_for_deoptimization());
612  DCHECK(function->shared()->is_compiled());
613  return Handle<Code>(code, feedback_vector->GetIsolate());
614  }
615  }
616  }
617  return MaybeHandle<Code>();
618 }
619 
620 void ClearOptimizedCodeCache(OptimizedCompilationInfo* compilation_info) {
621  Handle<JSFunction> function = compilation_info->closure();
622  if (compilation_info->osr_offset().IsNone()) {
623  Handle<FeedbackVector> vector =
624  handle(function->feedback_vector(), function->GetIsolate());
625  vector->ClearOptimizationMarker();
626  }
627 }
628 
629 void InsertCodeIntoOptimizedCodeCache(
630  OptimizedCompilationInfo* compilation_info) {
631  Handle<Code> code = compilation_info->code();
632  if (code->kind() != Code::OPTIMIZED_FUNCTION) return; // Nothing to do.
633 
634  // Function context specialization folds-in the function context,
635  // so no sharing can occur.
636  if (compilation_info->is_function_context_specializing()) {
637  // Native context specialized code is not shared, so make sure the optimized
638  // code cache is clear.
639  ClearOptimizedCodeCache(compilation_info);
640  return;
641  }
642 
643  // Cache optimized context-specific code.
644  Handle<JSFunction> function = compilation_info->closure();
645  Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate());
646  Handle<Context> native_context(function->context()->native_context(),
647  function->GetIsolate());
648  if (compilation_info->osr_offset().IsNone()) {
649  Handle<FeedbackVector> vector =
650  handle(function->feedback_vector(), function->GetIsolate());
651  FeedbackVector::SetOptimizedCode(vector, code);
652  }
653 }
654 
655 bool GetOptimizedCodeNow(OptimizedCompilationJob* job, Isolate* isolate) {
656  TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
657  RuntimeCallTimerScope runtimeTimer(
658  isolate, RuntimeCallCounterId::kRecompileSynchronous);
659  OptimizedCompilationInfo* compilation_info = job->compilation_info();
660  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
661  "V8.RecompileSynchronous");
662 
663  if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED ||
664  job->ExecuteJob() != CompilationJob::SUCCEEDED ||
665  job->FinalizeJob(isolate) != CompilationJob::SUCCEEDED) {
666  if (FLAG_trace_opt) {
667  PrintF("[aborted optimizing ");
668  compilation_info->closure()->ShortPrint();
669  PrintF(" because: %s]\n",
670  GetBailoutReason(compilation_info->bailout_reason()));
671  }
672  return false;
673  }
674 
675  // Success!
676  job->RecordCompilationStats();
677  DCHECK(!isolate->has_pending_exception());
678  InsertCodeIntoOptimizedCodeCache(compilation_info);
679  job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, isolate);
680  return true;
681 }
682 
683 bool GetOptimizedCodeLater(OptimizedCompilationJob* job, Isolate* isolate) {
684  OptimizedCompilationInfo* compilation_info = job->compilation_info();
685  if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) {
686  if (FLAG_trace_concurrent_recompilation) {
687  PrintF(" ** Compilation queue full, will retry optimizing ");
688  compilation_info->closure()->ShortPrint();
689  PrintF(" later.\n");
690  }
691  return false;
692  }
693 
694  if (isolate->heap()->HighMemoryPressure()) {
695  if (FLAG_trace_concurrent_recompilation) {
696  PrintF(" ** High memory pressure, will retry optimizing ");
697  compilation_info->closure()->ShortPrint();
698  PrintF(" later.\n");
699  }
700  return false;
701  }
702 
703  TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
704  RuntimeCallTimerScope runtimeTimer(
705  isolate, RuntimeCallCounterId::kRecompileSynchronous);
706  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
707  "V8.RecompileSynchronous");
708 
709  if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED) return false;
710  isolate->optimizing_compile_dispatcher()->QueueForOptimization(job);
711 
712  if (FLAG_trace_concurrent_recompilation) {
713  PrintF(" ** Queued ");
714  compilation_info->closure()->ShortPrint();
715  PrintF(" for concurrent optimization.\n");
716  }
717  return true;
718 }
719 
720 MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
721  ConcurrencyMode mode,
722  BailoutId osr_offset = BailoutId::None(),
723  JavaScriptFrame* osr_frame = nullptr) {
724  Isolate* isolate = function->GetIsolate();
725  Handle<SharedFunctionInfo> shared(function->shared(), isolate);
726 
727  // Make sure we clear the optimization marker on the function so that we
728  // don't try to re-optimize.
729  if (function->HasOptimizationMarker()) {
730  function->ClearOptimizationMarker();
731  }
732 
733  if (isolate->debug()->needs_check_on_function_call()) {
734  // Do not optimize when debugger needs to hook into every call.
735  return MaybeHandle<Code>();
736  }
737 
738  Handle<Code> cached_code;
739  if (GetCodeFromOptimizedCodeCache(function, osr_offset)
740  .ToHandle(&cached_code)) {
741  if (FLAG_trace_opt) {
742  PrintF("[found optimized code for ");
743  function->ShortPrint();
744  if (!osr_offset.IsNone()) {
745  PrintF(" at OSR AST id %d", osr_offset.ToInt());
746  }
747  PrintF("]\n");
748  }
749  return cached_code;
750  }
751 
752  // Reset profiler ticks, function is no longer considered hot.
753  DCHECK(shared->is_compiled());
754  function->feedback_vector()->set_profiler_ticks(0);
755 
756  VMState<COMPILER> state(isolate);
757  DCHECK(!isolate->has_pending_exception());
758  PostponeInterruptsScope postpone(isolate);
759  bool has_script = shared->script()->IsScript();
760  // BUG(5946): This DCHECK is necessary to make certain that we won't
761  // tolerate the lack of a script without bytecode.
762  DCHECK_IMPLIES(!has_script, shared->HasBytecodeArray());
763  std::unique_ptr<OptimizedCompilationJob> job(
764  compiler::Pipeline::NewCompilationJob(isolate, function, has_script));
765  OptimizedCompilationInfo* compilation_info = job->compilation_info();
766 
767  compilation_info->SetOptimizingForOsr(osr_offset, osr_frame);
768 
769  // Do not use TurboFan if we need to be able to set break points.
770  if (compilation_info->shared_info()->HasBreakInfo()) {
771  compilation_info->AbortOptimization(BailoutReason::kFunctionBeingDebugged);
772  return MaybeHandle<Code>();
773  }
774 
775  // Do not use TurboFan when %NeverOptimizeFunction was applied.
776  if (shared->optimization_disabled() &&
777  shared->disable_optimization_reason() ==
778  BailoutReason::kOptimizationDisabledForTest) {
779  compilation_info->AbortOptimization(
780  BailoutReason::kOptimizationDisabledForTest);
781  return MaybeHandle<Code>();
782  }
783 
784  // Do not use TurboFan if optimization is disabled or function doesn't pass
785  // turbo_filter.
786  if (!FLAG_opt || !shared->PassesFilter(FLAG_turbo_filter)) {
787  compilation_info->AbortOptimization(BailoutReason::kOptimizationDisabled);
788  return MaybeHandle<Code>();
789  }
790 
791  TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate);
792  RuntimeCallTimerScope runtimeTimer(isolate,
793  RuntimeCallCounterId::kOptimizeCode);
794  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.OptimizeCode");
795 
796  // In case of concurrent recompilation, all handles below this point will be
797  // allocated in a deferred handle scope that is detached and handed off to
798  // the background thread when we return.
799  base::Optional<CompilationHandleScope> compilation;
800  if (mode == ConcurrencyMode::kConcurrent) {
801  compilation.emplace(isolate, compilation_info);
802  }
803 
804  // All handles below will be canonicalized.
805  CanonicalHandleScope canonical(isolate);
806 
807  // Reopen handles in the new CompilationHandleScope.
808  compilation_info->ReopenHandlesInNewHandleScope(isolate);
809 
810  if (mode == ConcurrencyMode::kConcurrent) {
811  if (GetOptimizedCodeLater(job.get(), isolate)) {
812  job.release(); // The background recompile job owns this now.
813 
814  // Set the optimization marker and return a code object which checks it.
815  function->SetOptimizationMarker(OptimizationMarker::kInOptimizationQueue);
816  DCHECK(function->IsInterpreted() ||
817  (!function->is_compiled() && function->shared()->IsInterpreted()));
818  DCHECK(function->shared()->HasBytecodeArray());
819  return BUILTIN_CODE(isolate, InterpreterEntryTrampoline);
820  }
821  } else {
822  if (GetOptimizedCodeNow(job.get(), isolate))
823  return compilation_info->code();
824  }
825 
826  if (isolate->has_pending_exception()) isolate->clear_pending_exception();
827  return MaybeHandle<Code>();
828 }
829 
830 bool FailWithPendingException(Isolate* isolate, ParseInfo* parse_info,
831  Compiler::ClearExceptionFlag flag) {
832  if (flag == Compiler::CLEAR_EXCEPTION) {
833  isolate->clear_pending_exception();
834  } else if (!isolate->has_pending_exception()) {
835  if (parse_info->pending_error_handler()->has_pending_error()) {
836  parse_info->pending_error_handler()->ReportErrors(
837  isolate, parse_info->script(), parse_info->ast_value_factory());
838  } else {
839  isolate->StackOverflow();
840  }
841  }
842  return false;
843 }
844 
845 void FinalizeScriptCompilation(Isolate* isolate, ParseInfo* parse_info) {
846  Handle<Script> script = parse_info->script();
847  script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
848 
849  // Register any pending parallel tasks with the associated SFI.
850  if (parse_info->parallel_tasks()) {
851  CompilerDispatcher* dispatcher = parse_info->parallel_tasks()->dispatcher();
852  for (auto& it : *parse_info->parallel_tasks()) {
853  FunctionLiteral* literal = it.first;
854  CompilerDispatcher::JobId job_id = it.second;
855  MaybeHandle<SharedFunctionInfo> maybe_shared_for_task =
856  script->FindSharedFunctionInfo(isolate, literal);
857  Handle<SharedFunctionInfo> shared_for_task;
858  if (maybe_shared_for_task.ToHandle(&shared_for_task)) {
859  dispatcher->RegisterSharedFunctionInfo(job_id, *shared_for_task);
860  } else {
861  dispatcher->AbortJob(job_id);
862  }
863  }
864  }
865 }
866 
867 MaybeHandle<SharedFunctionInfo> FinalizeTopLevel(
868  ParseInfo* parse_info, Isolate* isolate,
869  UnoptimizedCompilationJob* outer_function_job,
870  UnoptimizedCompilationJobList* inner_function_jobs) {
871  // Internalize ast values onto the heap.
872  parse_info->ast_value_factory()->Internalize(isolate);
873 
874  // Create shared function infos for top level and shared function infos array
875  // for inner functions.
876  EnsureSharedFunctionInfosArrayOnScript(parse_info, isolate);
877  DCHECK_EQ(kNoSourcePosition,
878  parse_info->literal()->function_token_position());
879  Handle<SharedFunctionInfo> shared_info =
880  isolate->factory()->NewSharedFunctionInfoForLiteral(
881  parse_info->literal(), parse_info->script(), true);
882 
883  // Finalize compilation of the unoptimized bytecode or asm-js data.
884  if (!FinalizeUnoptimizedCode(parse_info, isolate, shared_info,
885  outer_function_job, inner_function_jobs)) {
886  FailWithPendingException(isolate, parse_info,
887  Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
888  return MaybeHandle<SharedFunctionInfo>();
889  }
890 
891  FinalizeScriptCompilation(isolate, parse_info);
892 
893  return shared_info;
894 }
895 
896 MaybeHandle<SharedFunctionInfo> CompileToplevel(ParseInfo* parse_info,
897  Isolate* isolate) {
898  TimerEventScope<TimerEventCompileCode> top_level_timer(isolate);
899  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
900  DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
901 
902  PostponeInterruptsScope postpone(isolate);
903  DCHECK(!isolate->native_context().is_null());
904  RuntimeCallTimerScope runtimeTimer(
905  isolate, parse_info->is_eval() ? RuntimeCallCounterId::kCompileEval
906  : RuntimeCallCounterId::kCompileScript);
907  VMState<BYTECODE_COMPILER> state(isolate);
908  if (parse_info->literal() == nullptr &&
909  !parsing::ParseProgram(parse_info, isolate)) {
910  return MaybeHandle<SharedFunctionInfo>();
911  }
912  // Measure how long it takes to do the compilation; only take the
913  // rest of the function into account to avoid overlap with the
914  // parsing statistics.
915  HistogramTimer* rate = parse_info->is_eval()
916  ? isolate->counters()->compile_eval()
917  : isolate->counters()->compile();
918  HistogramTimerScope timer(rate);
919  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
920  parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile");
921 
922  // Generate the unoptimized bytecode or asm-js data.
923  MaybeHandle<SharedFunctionInfo> shared_info =
924  GenerateUnoptimizedCodeForToplevel(isolate, parse_info,
925  isolate->allocator());
926  if (shared_info.is_null()) {
927  FailWithPendingException(isolate, parse_info,
928  Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
929  return MaybeHandle<SharedFunctionInfo>();
930  }
931 
932  FinalizeScriptCompilation(isolate, parse_info);
933  return shared_info;
934 }
935 
936 std::unique_ptr<UnoptimizedCompilationJob> CompileOnBackgroundThread(
937  ParseInfo* parse_info, AccountingAllocator* allocator,
938  UnoptimizedCompilationJobList* inner_function_jobs) {
939  DisallowHeapAccess no_heap_access;
940  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
941  "V8.CompileCodeBackground");
942  RuntimeCallTimerScope runtimeTimer(
943  parse_info->runtime_call_stats(),
944  parse_info->is_toplevel()
945  ? parse_info->is_eval()
946  ? RuntimeCallCounterId::kCompileBackgroundEval
947  : RuntimeCallCounterId::kCompileBackgroundScript
948  : RuntimeCallCounterId::kCompileBackgroundFunction);
949 
950  // Generate the unoptimized bytecode or asm-js data.
951  std::unique_ptr<UnoptimizedCompilationJob> outer_function_job(
952  GenerateUnoptimizedCode(parse_info, allocator, inner_function_jobs));
953  return outer_function_job;
954 }
955 
956 } // namespace
957 
958 BackgroundCompileTask::BackgroundCompileTask(ScriptStreamingData* streamed_data,
959  Isolate* isolate)
960  : info_(new ParseInfo(isolate)),
961  stack_size_(i::FLAG_stack_size),
962  worker_thread_runtime_call_stats_(
963  isolate->counters()->worker_thread_runtime_call_stats()),
964  allocator_(isolate->allocator()),
965  timer_(isolate->counters()->compile_script_on_background()) {
966  VMState<PARSER> state(isolate);
967 
968  // Prepare the data for the internalization phase and compilation phase, which
969  // will happen in the main thread after parsing.
970  LOG(isolate, ScriptEvent(Logger::ScriptEventType::kStreamingCompile,
971  info_->script_id()));
972  info_->set_toplevel();
973  info_->set_allow_lazy_parsing();
974  if (V8_UNLIKELY(info_->block_coverage_enabled())) {
975  info_->AllocateSourceRangeMap();
976  }
977  LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
978  info_->set_language_mode(
979  stricter_language_mode(info_->language_mode(), language_mode));
980 
981  std::unique_ptr<Utf16CharacterStream> stream(ScannerStream::For(
982  streamed_data->source_stream.get(), streamed_data->encoding));
983  info_->set_character_stream(std::move(stream));
984 }
985 
986 BackgroundCompileTask::BackgroundCompileTask(
987  AccountingAllocator* allocator, const ParseInfo* outer_parse_info,
988  const AstRawString* function_name, const FunctionLiteral* function_literal,
989  WorkerThreadRuntimeCallStats* worker_thread_runtime_stats,
990  TimedHistogram* timer, int max_stack_size)
991  : info_(ParseInfo::FromParent(outer_parse_info, allocator, function_literal,
992  function_name)),
993  stack_size_(max_stack_size),
994  worker_thread_runtime_call_stats_(worker_thread_runtime_stats),
995  allocator_(allocator),
996  timer_(timer) {
997  DCHECK(outer_parse_info->is_toplevel());
998  DCHECK(!function_literal->is_toplevel());
999 
1000  // Clone the character stream so both can be accessed independently.
1001  std::unique_ptr<Utf16CharacterStream> character_stream =
1002  outer_parse_info->character_stream()->Clone();
1003  character_stream->Seek(function_literal->start_position());
1004  info_->set_character_stream(std::move(character_stream));
1005 
1006  // Get preparsed scope data from the function literal.
1007  if (function_literal->produced_preparsed_scope_data()) {
1008  ZonePreParsedScopeData* serialized_data =
1009  function_literal->produced_preparsed_scope_data()->Serialize(
1010  info_->zone());
1011  info_->set_consumed_preparsed_scope_data(
1012  ConsumedPreParsedScopeData::For(info_->zone(), serialized_data));
1013  }
1014 }
1015 
1016 BackgroundCompileTask::~BackgroundCompileTask() = default;
1017 
1018 namespace {
1019 
1020 // A scope object that ensures a parse info's runtime call stats, stack limit
1021 // and on_background_thread fields is set correctly during worker-thread
1022 // compile, and restores it after going out of scope.
1023 class OffThreadParseInfoScope {
1024  public:
1025  OffThreadParseInfoScope(
1026  ParseInfo* parse_info,
1027  WorkerThreadRuntimeCallStats* worker_thread_runtime_stats, int stack_size)
1028  : parse_info_(parse_info),
1029  original_runtime_call_stats_(parse_info_->runtime_call_stats()),
1030  original_stack_limit_(parse_info_->stack_limit()),
1031  worker_thread_scope_(worker_thread_runtime_stats) {
1032  parse_info_->set_on_background_thread(true);
1033  parse_info_->set_runtime_call_stats(worker_thread_scope_.Get());
1034  parse_info_->set_stack_limit(GetCurrentStackPosition() - stack_size * KB);
1035  }
1036 
1037  ~OffThreadParseInfoScope() {
1038  parse_info_->set_stack_limit(original_stack_limit_);
1039  parse_info_->set_runtime_call_stats(original_runtime_call_stats_);
1040  parse_info_->set_on_background_thread(false);
1041  }
1042 
1043  private:
1044  ParseInfo* parse_info_;
1045  RuntimeCallStats* original_runtime_call_stats_;
1046  uintptr_t original_stack_limit_;
1047  WorkerThreadRuntimeCallStatsScope worker_thread_scope_;
1048 
1049  DISALLOW_COPY_AND_ASSIGN(OffThreadParseInfoScope);
1050 };
1051 
1052 } // namespace
1053 
1054 void BackgroundCompileTask::Run() {
1055  DisallowHeapAllocation no_allocation;
1056  DisallowHandleAllocation no_handles;
1057  DisallowHeapAccess no_heap_access;
1058 
1059  TimedHistogramScope timer(timer_);
1060  OffThreadParseInfoScope off_thread_scope(
1061  info_.get(), worker_thread_runtime_call_stats_, stack_size_);
1062  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1063  "BackgroundCompileTask::Run");
1064  RuntimeCallTimerScope runtimeTimer(
1065  info_->runtime_call_stats(),
1066  RuntimeCallCounterId::kCompileBackgroundCompileTask);
1067 
1068  // Update the character stream's runtime call stats.
1069  info_->character_stream()->set_runtime_call_stats(
1070  info_->runtime_call_stats());
1071 
1072  // Parser needs to stay alive for finalizing the parsing on the main
1073  // thread.
1074  parser_.reset(new Parser(info_.get()));
1075  parser_->InitializeEmptyScopeChain(info_.get());
1076 
1077  parser_->ParseOnBackground(info_.get());
1078  if (info_->literal() != nullptr) {
1079  // Parsing has succeeded, compile.
1080  outer_function_job_ = CompileOnBackgroundThread(info_.get(), allocator_,
1081  &inner_function_jobs_);
1082  }
1083 }
1084 
1085 
1086 // ----------------------------------------------------------------------------
1087 // Implementation of Compiler
1088 
1089 bool Compiler::Analyze(ParseInfo* parse_info) {
1090  DCHECK_NOT_NULL(parse_info->literal());
1091  RuntimeCallTimerScope runtimeTimer(
1092  parse_info->runtime_call_stats(),
1093  parse_info->on_background_thread()
1094  ? RuntimeCallCounterId::kCompileBackgroundAnalyse
1095  : RuntimeCallCounterId::kCompileAnalyse);
1096  if (!Rewriter::Rewrite(parse_info)) return false;
1097  if (!DeclarationScope::Analyze(parse_info)) return false;
1098  return true;
1099 }
1100 
1101 bool Compiler::ParseAndAnalyze(ParseInfo* parse_info,
1102  Handle<SharedFunctionInfo> shared_info,
1103  Isolate* isolate) {
1104  if (!parsing::ParseAny(parse_info, shared_info, isolate)) {
1105  return false;
1106  }
1107  return Compiler::Analyze(parse_info);
1108 }
1109 
1110 bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
1111  ClearExceptionFlag flag) {
1112  // We should never reach here if the function is already compiled.
1113  DCHECK(!shared_info->is_compiled());
1114 
1115  Isolate* isolate = shared_info->GetIsolate();
1116  DCHECK(AllowCompilation::IsAllowed(isolate));
1117  DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
1118  DCHECK(!isolate->has_pending_exception());
1119  DCHECK(!shared_info->HasBytecodeArray());
1120  VMState<BYTECODE_COMPILER> state(isolate);
1121  PostponeInterruptsScope postpone(isolate);
1122  TimerEventScope<TimerEventCompileCode> compile_timer(isolate);
1123  RuntimeCallTimerScope runtimeTimer(isolate,
1124  RuntimeCallCounterId::kCompileFunction);
1125  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
1126  AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
1127 
1128  // Set up parse info.
1129  ParseInfo parse_info(isolate, shared_info);
1130  parse_info.set_lazy_compile();
1131 
1132  // Check if the compiler dispatcher has shared_info enqueued for compile.
1133  CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
1134  if (dispatcher->IsEnqueued(shared_info)) {
1135  if (!dispatcher->FinishNow(shared_info)) {
1136  return FailWithPendingException(isolate, &parse_info, flag);
1137  }
1138  return true;
1139  }
1140 
1141  if (shared_info->HasUncompiledDataWithPreParsedScope()) {
1142  parse_info.set_consumed_preparsed_scope_data(
1143  ConsumedPreParsedScopeData::For(
1144  isolate, handle(shared_info->uncompiled_data_with_pre_parsed_scope()
1145  ->pre_parsed_scope_data(),
1146  isolate)));
1147  }
1148 
1149  // Parse and update ParseInfo with the results.
1150  if (!parsing::ParseFunction(&parse_info, shared_info, isolate)) {
1151  return FailWithPendingException(isolate, &parse_info, flag);
1152  }
1153 
1154  // Generate the unoptimized bytecode or asm-js data.
1155  UnoptimizedCompilationJobList inner_function_jobs;
1156  std::unique_ptr<UnoptimizedCompilationJob> outer_function_job(
1157  GenerateUnoptimizedCode(&parse_info, isolate->allocator(),
1158  &inner_function_jobs));
1159  if (!outer_function_job) {
1160  return FailWithPendingException(isolate, &parse_info, flag);
1161  }
1162 
1163  // Internalize ast values onto the heap.
1164  parse_info.ast_value_factory()->Internalize(isolate);
1165 
1166  // Finalize compilation of the unoptimized bytecode or asm-js data.
1167  if (!FinalizeUnoptimizedCode(&parse_info, isolate, shared_info,
1168  outer_function_job.get(),
1169  &inner_function_jobs)) {
1170  return FailWithPendingException(isolate, &parse_info, flag);
1171  }
1172 
1173  DCHECK(!isolate->has_pending_exception());
1174  return true;
1175 }
1176 
1177 bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) {
1178  // We should never reach here if the function is already compiled or optimized
1179  DCHECK(!function->is_compiled());
1180  DCHECK(!function->IsOptimized());
1181  DCHECK(!function->HasOptimizationMarker());
1182  DCHECK(!function->HasOptimizedCode());
1183 
1184  Isolate* isolate = function->GetIsolate();
1185  Handle<SharedFunctionInfo> shared_info = handle(function->shared(), isolate);
1186 
1187  // Ensure shared function info is compiled.
1188  if (!shared_info->is_compiled() && !Compile(shared_info, flag)) return false;
1189  Handle<Code> code = handle(shared_info->GetCode(), isolate);
1190 
1191  // Allocate FeedbackVector for the JSFunction.
1192  JSFunction::EnsureFeedbackVector(function);
1193 
1194  // Optimize now if --always-opt is enabled.
1195  if (FLAG_always_opt && !function->shared()->HasAsmWasmData()) {
1196  if (FLAG_trace_opt) {
1197  PrintF("[optimizing ");
1198  function->ShortPrint();
1199  PrintF(" because --always-opt]\n");
1200  }
1201  Handle<Code> opt_code;
1202  if (GetOptimizedCode(function, ConcurrencyMode::kNotConcurrent)
1203  .ToHandle(&opt_code)) {
1204  code = opt_code;
1205  }
1206  }
1207 
1208  // Install code on closure.
1209  function->set_code(*code);
1210 
1211  // Check postconditions on success.
1212  DCHECK(!isolate->has_pending_exception());
1213  DCHECK(function->shared()->is_compiled());
1214  DCHECK(function->is_compiled());
1215  return true;
1216 }
1217 
1218 bool Compiler::FinalizeBackgroundCompileTask(
1219  BackgroundCompileTask* task, Handle<SharedFunctionInfo> shared_info,
1220  Isolate* isolate, ClearExceptionFlag flag) {
1221  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1222  "V8.FinalizeBackgroundCompileTask");
1223  RuntimeCallTimerScope runtimeTimer(
1224  isolate, RuntimeCallCounterId::kCompileFinalizeBackgroundCompileTask);
1225  HandleScope scope(isolate);
1226  ParseInfo* parse_info = task->info();
1227  DCHECK(!parse_info->is_toplevel());
1228  DCHECK(!shared_info->is_compiled());
1229 
1230  Handle<Script> script(Script::cast(shared_info->script()), isolate);
1231  parse_info->set_script(script);
1232 
1233  task->parser()->UpdateStatistics(isolate, script);
1234  task->parser()->HandleSourceURLComments(isolate, script);
1235 
1236  if (parse_info->literal() == nullptr || !task->outer_function_job()) {
1237  // Parsing or compile failed on background thread - report error messages.
1238  return FailWithPendingException(isolate, parse_info, flag);
1239  }
1240 
1241  // Parsing has succeeded - finalize compilation.
1242  parse_info->ast_value_factory()->Internalize(isolate);
1243  if (!FinalizeUnoptimizedCode(parse_info, isolate, shared_info,
1244  task->outer_function_job(),
1245  task->inner_function_jobs())) {
1246  // Finalization failed - throw an exception.
1247  return FailWithPendingException(isolate, parse_info, flag);
1248  }
1249 
1250  DCHECK(!isolate->has_pending_exception());
1251  DCHECK(shared_info->is_compiled());
1252  return true;
1253 }
1254 
1255 bool Compiler::CompileOptimized(Handle<JSFunction> function,
1256  ConcurrencyMode mode) {
1257  if (function->IsOptimized()) return true;
1258  Isolate* isolate = function->GetIsolate();
1259  DCHECK(AllowCompilation::IsAllowed(isolate));
1260 
1261  // Start a compilation.
1262  Handle<Code> code;
1263  if (!GetOptimizedCode(function, mode).ToHandle(&code)) {
1264  // Optimization failed, get unoptimized code. Unoptimized code must exist
1265  // already if we are optimizing.
1266  DCHECK(!isolate->has_pending_exception());
1267  DCHECK(function->shared()->is_compiled());
1268  DCHECK(function->shared()->IsInterpreted());
1269  code = BUILTIN_CODE(isolate, InterpreterEntryTrampoline);
1270  }
1271 
1272  // Install code on closure.
1273  function->set_code(*code);
1274 
1275  // Check postconditions on success.
1276  DCHECK(!isolate->has_pending_exception());
1277  DCHECK(function->shared()->is_compiled());
1278  DCHECK(function->is_compiled());
1279  DCHECK_IMPLIES(function->HasOptimizationMarker(),
1280  function->IsInOptimizationQueue());
1281  DCHECK_IMPLIES(function->HasOptimizationMarker(),
1282  function->ChecksOptimizationMarker());
1283  DCHECK_IMPLIES(function->IsInOptimizationQueue(),
1284  mode == ConcurrencyMode::kConcurrent);
1285  return true;
1286 }
1287 
1288 MaybeHandle<SharedFunctionInfo> Compiler::CompileForLiveEdit(
1289  ParseInfo* parse_info, Isolate* isolate) {
1290  return CompileToplevel(parse_info, isolate);
1291 }
1292 
1293 MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
1294  Handle<String> source, Handle<SharedFunctionInfo> outer_info,
1295  Handle<Context> context, LanguageMode language_mode,
1296  ParseRestriction restriction, int parameters_end_pos,
1297  int eval_scope_position, int eval_position) {
1298  Isolate* isolate = context->GetIsolate();
1299  int source_length = source->length();
1300  isolate->counters()->total_eval_size()->Increment(source_length);
1301  isolate->counters()->total_compile_size()->Increment(source_length);
1302 
1303  // The cache lookup key needs to be aware of the separation between the
1304  // parameters and the body to prevent this valid invocation:
1305  // Function("", "function anonymous(\n/**/) {\n}");
1306  // from adding an entry that falsely approves this invalid invocation:
1307  // Function("\n/**/) {\nfunction anonymous(", "}");
1308  // The actual eval_scope_position for indirect eval and CreateDynamicFunction
1309  // is unused (just 0), which means it's an available field to use to indicate
1310  // this separation. But to make sure we're not causing other false hits, we
1311  // negate the scope position.
1312  if (restriction == ONLY_SINGLE_FUNCTION_LITERAL &&
1313  parameters_end_pos != kNoSourcePosition) {
1314  // use the parameters_end_pos as the eval_scope_position in the eval cache.
1315  DCHECK_EQ(eval_scope_position, 0);
1316  eval_scope_position = -parameters_end_pos;
1317  }
1318  CompilationCache* compilation_cache = isolate->compilation_cache();
1319  InfoCellPair eval_result = compilation_cache->LookupEval(
1320  source, outer_info, context, language_mode, eval_scope_position);
1321  Handle<FeedbackCell> feedback_cell;
1322  if (eval_result.has_feedback_cell()) {
1323  feedback_cell = handle(eval_result.feedback_cell(), isolate);
1324  }
1325 
1326  Handle<SharedFunctionInfo> shared_info;
1327  Handle<Script> script;
1328  bool allow_eval_cache;
1329  if (eval_result.has_shared()) {
1330  shared_info = Handle<SharedFunctionInfo>(eval_result.shared(), isolate);
1331  script = Handle<Script>(Script::cast(shared_info->script()), isolate);
1332  allow_eval_cache = true;
1333  } else {
1334  ParseInfo parse_info(isolate);
1335  script = parse_info.CreateScript(
1336  isolate, source, OriginOptionsForEval(outer_info->script()));
1337  script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
1338  script->set_eval_from_shared(*outer_info);
1339  if (eval_position == kNoSourcePosition) {
1340  // If the position is missing, attempt to get the code offset by
1341  // walking the stack. Do not translate the code offset into source
1342  // position, but store it as negative value for lazy translation.
1343  StackTraceFrameIterator it(isolate);
1344  if (!it.done() && it.is_javascript()) {
1345  FrameSummary summary = FrameSummary::GetTop(it.javascript_frame());
1346  script->set_eval_from_shared(
1347  summary.AsJavaScript().function()->shared());
1348  script->set_origin_options(OriginOptionsForEval(*summary.script()));
1349  eval_position = -summary.code_offset();
1350  } else {
1351  eval_position = 0;
1352  }
1353  }
1354  script->set_eval_from_position(eval_position);
1355 
1356  parse_info.set_eval();
1357  parse_info.set_language_mode(language_mode);
1358  parse_info.set_parse_restriction(restriction);
1359  parse_info.set_parameters_end_pos(parameters_end_pos);
1360  if (!context->IsNativeContext()) {
1361  parse_info.set_outer_scope_info(handle(context->scope_info(), isolate));
1362  }
1363  DCHECK(!parse_info.is_module());
1364 
1365  if (!CompileToplevel(&parse_info, isolate).ToHandle(&shared_info)) {
1366  return MaybeHandle<JSFunction>();
1367  }
1368  allow_eval_cache = parse_info.allow_eval_cache();
1369  }
1370 
1371  // If caller is strict mode, the result must be in strict mode as well.
1372  DCHECK(is_sloppy(language_mode) || is_strict(shared_info->language_mode()));
1373 
1374  Handle<JSFunction> result;
1375  if (eval_result.has_shared()) {
1376  if (eval_result.has_feedback_cell()) {
1377  result = isolate->factory()->NewFunctionFromSharedFunctionInfo(
1378  shared_info, context, feedback_cell, NOT_TENURED);
1379  } else {
1380  result = isolate->factory()->NewFunctionFromSharedFunctionInfo(
1381  shared_info, context, NOT_TENURED);
1382  JSFunction::EnsureFeedbackVector(result);
1383  if (allow_eval_cache) {
1384  // Make sure to cache this result.
1385  Handle<FeedbackCell> new_feedback_cell(result->feedback_cell(),
1386  isolate);
1387  compilation_cache->PutEval(source, outer_info, context, shared_info,
1388  new_feedback_cell, eval_scope_position);
1389  }
1390  }
1391  } else {
1392  result = isolate->factory()->NewFunctionFromSharedFunctionInfo(
1393  shared_info, context, NOT_TENURED);
1394  JSFunction::EnsureFeedbackVector(result);
1395  if (allow_eval_cache) {
1396  // Add the SharedFunctionInfo and the LiteralsArray to the eval cache if
1397  // we didn't retrieve from there.
1398  Handle<FeedbackCell> new_feedback_cell(result->feedback_cell(), isolate);
1399  compilation_cache->PutEval(source, outer_info, context, shared_info,
1400  new_feedback_cell, eval_scope_position);
1401  }
1402  }
1403 
1404  return result;
1405 }
1406 
1407 
1408 bool Compiler::CodeGenerationFromStringsAllowed(Isolate* isolate,
1409  Handle<Context> context,
1410  Handle<String> source) {
1411  DCHECK(context->allow_code_gen_from_strings()->IsFalse(isolate));
1412  // Check with callback if set.
1413  AllowCodeGenerationFromStringsCallback callback =
1414  isolate->allow_code_gen_callback();
1415  if (callback == nullptr) {
1416  // No callback set and code generation disallowed.
1417  return false;
1418  } else {
1419  // Callback set. Let it decide if code generation is allowed.
1420  VMState<EXTERNAL> state(isolate);
1421  return callback(v8::Utils::ToLocal(context), v8::Utils::ToLocal(source));
1422  }
1423 }
1424 
1425 MaybeHandle<JSFunction> Compiler::GetFunctionFromString(
1426  Handle<Context> context, Handle<String> source,
1427  ParseRestriction restriction, int parameters_end_pos) {
1428  Isolate* const isolate = context->GetIsolate();
1429  Handle<Context> native_context(context->native_context(), isolate);
1430 
1431  // Check if native context allows code generation from
1432  // strings. Throw an exception if it doesn't.
1433  if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) &&
1434  !CodeGenerationFromStringsAllowed(isolate, native_context, source)) {
1435  Handle<Object> error_message =
1436  native_context->ErrorMessageForCodeGenerationFromStrings();
1437  THROW_NEW_ERROR(isolate, NewEvalError(MessageTemplate::kCodeGenFromStrings,
1438  error_message),
1439  JSFunction);
1440  }
1441 
1442  // Compile source string in the native context.
1443  int eval_scope_position = 0;
1444  int eval_position = kNoSourcePosition;
1445  Handle<SharedFunctionInfo> outer_info(
1446  native_context->empty_function()->shared(), isolate);
1447  return Compiler::GetFunctionFromEval(
1448  source, outer_info, native_context, LanguageMode::kSloppy, restriction,
1449  parameters_end_pos, eval_scope_position, eval_position);
1450 }
1451 
1452 namespace {
1453 
1454 struct ScriptCompileTimerScope {
1455  public:
1456  // TODO(leszeks): There are too many blink-specific entries in this enum,
1457  // figure out a way to push produce/hit-isolate-cache/consume/consume-failed
1458  // back up the API and log them in blink instead.
1459  enum class CacheBehaviour {
1460  kProduceCodeCache,
1461  kHitIsolateCacheWhenNoCache,
1462  kConsumeCodeCache,
1463  kConsumeCodeCacheFailed,
1464  kNoCacheBecauseInlineScript,
1465  kNoCacheBecauseScriptTooSmall,
1466  kNoCacheBecauseCacheTooCold,
1467  kNoCacheNoReason,
1468  kNoCacheBecauseNoResource,
1469  kNoCacheBecauseInspector,
1470  kNoCacheBecauseCachingDisabled,
1471  kNoCacheBecauseModule,
1472  kNoCacheBecauseStreamingSource,
1473  kNoCacheBecauseV8Extension,
1474  kHitIsolateCacheWhenProduceCodeCache,
1475  kHitIsolateCacheWhenConsumeCodeCache,
1476  kNoCacheBecauseExtensionModule,
1477  kNoCacheBecausePacScript,
1478  kNoCacheBecauseInDocumentWrite,
1479  kNoCacheBecauseResourceWithNoCacheHandler,
1480  kHitIsolateCacheWhenStreamingSource,
1481  kCount
1482  };
1483 
1484  explicit ScriptCompileTimerScope(
1485  Isolate* isolate, ScriptCompiler::NoCacheReason no_cache_reason)
1486  : isolate_(isolate),
1487  all_scripts_histogram_scope_(isolate->counters()->compile_script(),
1488  true),
1489  no_cache_reason_(no_cache_reason),
1490  hit_isolate_cache_(false),
1491  producing_code_cache_(false),
1492  consuming_code_cache_(false),
1493  consuming_code_cache_failed_(false) {}
1494 
1495  ~ScriptCompileTimerScope() {
1496  CacheBehaviour cache_behaviour = GetCacheBehaviour();
1497 
1498  Histogram* cache_behaviour_histogram =
1499  isolate_->counters()->compile_script_cache_behaviour();
1500  // Sanity check that the histogram has exactly one bin per enum entry.
1501  DCHECK_EQ(0, cache_behaviour_histogram->min());
1502  DCHECK_EQ(static_cast<int>(CacheBehaviour::kCount),
1503  cache_behaviour_histogram->max() + 1);
1504  DCHECK_EQ(static_cast<int>(CacheBehaviour::kCount),
1505  cache_behaviour_histogram->num_buckets());
1506  cache_behaviour_histogram->AddSample(static_cast<int>(cache_behaviour));
1507 
1508  histogram_scope_.set_histogram(
1509  GetCacheBehaviourTimedHistogram(cache_behaviour));
1510  }
1511 
1512  void set_hit_isolate_cache() { hit_isolate_cache_ = true; }
1513 
1514  void set_producing_code_cache() { producing_code_cache_ = true; }
1515 
1516  void set_consuming_code_cache() { consuming_code_cache_ = true; }
1517 
1518  void set_consuming_code_cache_failed() {
1519  consuming_code_cache_failed_ = true;
1520  }
1521 
1522  private:
1523  Isolate* isolate_;
1524  LazyTimedHistogramScope histogram_scope_;
1525  // TODO(leszeks): This timer is the sum of the other times, consider removing
1526  // it to save space.
1527  HistogramTimerScope all_scripts_histogram_scope_;
1528  ScriptCompiler::NoCacheReason no_cache_reason_;
1529  bool hit_isolate_cache_;
1530  bool producing_code_cache_;
1531  bool consuming_code_cache_;
1532  bool consuming_code_cache_failed_;
1533 
1534  CacheBehaviour GetCacheBehaviour() {
1535  if (producing_code_cache_) {
1536  if (hit_isolate_cache_) {
1537  return CacheBehaviour::kHitIsolateCacheWhenProduceCodeCache;
1538  } else {
1539  return CacheBehaviour::kProduceCodeCache;
1540  }
1541  }
1542 
1543  if (consuming_code_cache_) {
1544  if (hit_isolate_cache_) {
1545  return CacheBehaviour::kHitIsolateCacheWhenConsumeCodeCache;
1546  } else if (consuming_code_cache_failed_) {
1547  return CacheBehaviour::kConsumeCodeCacheFailed;
1548  }
1549  return CacheBehaviour::kConsumeCodeCache;
1550  }
1551 
1552  if (hit_isolate_cache_) {
1553  if (no_cache_reason_ == ScriptCompiler::kNoCacheBecauseStreamingSource) {
1554  return CacheBehaviour::kHitIsolateCacheWhenStreamingSource;
1555  }
1556  return CacheBehaviour::kHitIsolateCacheWhenNoCache;
1557  }
1558 
1559  switch (no_cache_reason_) {
1560  case ScriptCompiler::kNoCacheBecauseInlineScript:
1561  return CacheBehaviour::kNoCacheBecauseInlineScript;
1562  case ScriptCompiler::kNoCacheBecauseScriptTooSmall:
1563  return CacheBehaviour::kNoCacheBecauseScriptTooSmall;
1564  case ScriptCompiler::kNoCacheBecauseCacheTooCold:
1565  return CacheBehaviour::kNoCacheBecauseCacheTooCold;
1566  case ScriptCompiler::kNoCacheNoReason:
1567  return CacheBehaviour::kNoCacheNoReason;
1568  case ScriptCompiler::kNoCacheBecauseNoResource:
1569  return CacheBehaviour::kNoCacheBecauseNoResource;
1570  case ScriptCompiler::kNoCacheBecauseInspector:
1571  return CacheBehaviour::kNoCacheBecauseInspector;
1572  case ScriptCompiler::kNoCacheBecauseCachingDisabled:
1573  return CacheBehaviour::kNoCacheBecauseCachingDisabled;
1574  case ScriptCompiler::kNoCacheBecauseModule:
1575  return CacheBehaviour::kNoCacheBecauseModule;
1576  case ScriptCompiler::kNoCacheBecauseStreamingSource:
1577  return CacheBehaviour::kNoCacheBecauseStreamingSource;
1578  case ScriptCompiler::kNoCacheBecauseV8Extension:
1579  return CacheBehaviour::kNoCacheBecauseV8Extension;
1580  case ScriptCompiler::kNoCacheBecauseExtensionModule:
1581  return CacheBehaviour::kNoCacheBecauseExtensionModule;
1582  case ScriptCompiler::kNoCacheBecausePacScript:
1583  return CacheBehaviour::kNoCacheBecausePacScript;
1584  case ScriptCompiler::kNoCacheBecauseInDocumentWrite:
1585  return CacheBehaviour::kNoCacheBecauseInDocumentWrite;
1586  case ScriptCompiler::kNoCacheBecauseResourceWithNoCacheHandler:
1587  return CacheBehaviour::kNoCacheBecauseResourceWithNoCacheHandler;
1588  case ScriptCompiler::kNoCacheBecauseDeferredProduceCodeCache: {
1589  if (hit_isolate_cache_) {
1590  return CacheBehaviour::kHitIsolateCacheWhenProduceCodeCache;
1591  } else {
1592  return CacheBehaviour::kProduceCodeCache;
1593  }
1594  }
1595  }
1596  UNREACHABLE();
1597  }
1598 
1599  TimedHistogram* GetCacheBehaviourTimedHistogram(
1600  CacheBehaviour cache_behaviour) {
1601  switch (cache_behaviour) {
1602  case CacheBehaviour::kProduceCodeCache:
1603  // Even if we hit the isolate's compilation cache, we currently recompile
1604  // when we want to produce the code cache.
1605  case CacheBehaviour::kHitIsolateCacheWhenProduceCodeCache:
1606  return isolate_->counters()->compile_script_with_produce_cache();
1607  case CacheBehaviour::kHitIsolateCacheWhenNoCache:
1608  case CacheBehaviour::kHitIsolateCacheWhenConsumeCodeCache:
1609  case CacheBehaviour::kHitIsolateCacheWhenStreamingSource:
1610  return isolate_->counters()->compile_script_with_isolate_cache_hit();
1611  case CacheBehaviour::kConsumeCodeCacheFailed:
1612  return isolate_->counters()->compile_script_consume_failed();
1613  case CacheBehaviour::kConsumeCodeCache:
1614  return isolate_->counters()->compile_script_with_consume_cache();
1615 
1616  case CacheBehaviour::kNoCacheBecauseInlineScript:
1617  return isolate_->counters()
1618  ->compile_script_no_cache_because_inline_script();
1619  case CacheBehaviour::kNoCacheBecauseScriptTooSmall:
1620  return isolate_->counters()
1621  ->compile_script_no_cache_because_script_too_small();
1622  case CacheBehaviour::kNoCacheBecauseCacheTooCold:
1623  return isolate_->counters()
1624  ->compile_script_no_cache_because_cache_too_cold();
1625 
1626  // Aggregate all the other "no cache" counters into a single histogram, to
1627  // save space.
1628  case CacheBehaviour::kNoCacheNoReason:
1629  case CacheBehaviour::kNoCacheBecauseNoResource:
1630  case CacheBehaviour::kNoCacheBecauseInspector:
1631  case CacheBehaviour::kNoCacheBecauseCachingDisabled:
1632  // TODO(leszeks): Consider counting separately once modules are more
1633  // common.
1634  case CacheBehaviour::kNoCacheBecauseModule:
1635  // TODO(leszeks): Count separately or remove entirely once we have
1636  // background compilation.
1637  case CacheBehaviour::kNoCacheBecauseStreamingSource:
1638  case CacheBehaviour::kNoCacheBecauseV8Extension:
1639  case CacheBehaviour::kNoCacheBecauseExtensionModule:
1640  case CacheBehaviour::kNoCacheBecausePacScript:
1641  case CacheBehaviour::kNoCacheBecauseInDocumentWrite:
1642  case CacheBehaviour::kNoCacheBecauseResourceWithNoCacheHandler:
1643  return isolate_->counters()->compile_script_no_cache_other();
1644 
1645  case CacheBehaviour::kCount:
1646  UNREACHABLE();
1647  }
1648  UNREACHABLE();
1649  }
1650 };
1651 
1652 Handle<Script> NewScript(Isolate* isolate, ParseInfo* parse_info,
1653  Handle<String> source,
1654  Compiler::ScriptDetails script_details,
1655  ScriptOriginOptions origin_options,
1656  NativesFlag natives) {
1657  // Create a script object describing the script to be compiled.
1658  Handle<Script> script =
1659  parse_info->CreateScript(isolate, source, origin_options, natives);
1660  Handle<Object> script_name;
1661  if (script_details.name_obj.ToHandle(&script_name)) {
1662  script->set_name(*script_name);
1663  script->set_line_offset(script_details.line_offset);
1664  script->set_column_offset(script_details.column_offset);
1665  }
1666  Handle<Object> source_map_url;
1667  if (script_details.source_map_url.ToHandle(&source_map_url)) {
1668  script->set_source_mapping_url(*source_map_url);
1669  }
1670  Handle<FixedArray> host_defined_options;
1671  if (script_details.host_defined_options.ToHandle(&host_defined_options)) {
1672  script->set_host_defined_options(*host_defined_options);
1673  }
1674  LOG(isolate, ScriptDetails(*script));
1675  return script;
1676 }
1677 
1678 } // namespace
1679 
1680 MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
1681  Isolate* isolate, Handle<String> source,
1682  const Compiler::ScriptDetails& script_details,
1683  ScriptOriginOptions origin_options, v8::Extension* extension,
1684  ScriptData* cached_data, ScriptCompiler::CompileOptions compile_options,
1685  ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives) {
1686  ScriptCompileTimerScope compile_timer(isolate, no_cache_reason);
1687 
1688  if (compile_options == ScriptCompiler::kNoCompileOptions ||
1689  compile_options == ScriptCompiler::kEagerCompile) {
1690  DCHECK_NULL(cached_data);
1691  } else {
1692  DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache);
1693  DCHECK(cached_data);
1694  DCHECK_NULL(extension);
1695  }
1696  int source_length = source->length();
1697  isolate->counters()->total_load_size()->Increment(source_length);
1698  isolate->counters()->total_compile_size()->Increment(source_length);
1699 
1700  LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
1701  CompilationCache* compilation_cache = isolate->compilation_cache();
1702 
1703  // Do a lookup in the compilation cache but not for extensions.
1704  MaybeHandle<SharedFunctionInfo> maybe_result;
1705  if (extension == nullptr) {
1706  bool can_consume_code_cache =
1707  compile_options == ScriptCompiler::kConsumeCodeCache;
1708  if (can_consume_code_cache) {
1709  compile_timer.set_consuming_code_cache();
1710  }
1711 
1712  // First check per-isolate compilation cache.
1713  maybe_result = compilation_cache->LookupScript(
1714  source, script_details.name_obj, script_details.line_offset,
1715  script_details.column_offset, origin_options, isolate->native_context(),
1716  language_mode);
1717  if (!maybe_result.is_null()) {
1718  compile_timer.set_hit_isolate_cache();
1719  } else if (can_consume_code_cache) {
1720  compile_timer.set_consuming_code_cache();
1721  // Then check cached code provided by embedder.
1722  HistogramTimerScope timer(isolate->counters()->compile_deserialize());
1723  RuntimeCallTimerScope runtimeTimer(
1724  isolate, RuntimeCallCounterId::kCompileDeserialize);
1725  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1726  "V8.CompileDeserialize");
1727  Handle<SharedFunctionInfo> inner_result;
1728  if (CodeSerializer::Deserialize(isolate, cached_data, source,
1729  origin_options)
1730  .ToHandle(&inner_result)) {
1731  // Promote to per-isolate compilation cache.
1732  DCHECK(inner_result->is_compiled());
1733  compilation_cache->PutScript(source, isolate->native_context(),
1734  language_mode, inner_result);
1735  Handle<Script> script(Script::cast(inner_result->script()), isolate);
1736  maybe_result = inner_result;
1737  } else {
1738  // Deserializer failed. Fall through to compile.
1739  compile_timer.set_consuming_code_cache_failed();
1740  }
1741  }
1742  }
1743 
1744  if (maybe_result.is_null()) {
1745  ParseInfo parse_info(isolate);
1746  // No cache entry found compile the script.
1747  NewScript(isolate, &parse_info, source, script_details, origin_options,
1748  natives);
1749 
1750  // Compile the function and add it to the isolate cache.
1751  if (origin_options.IsModule()) parse_info.set_module();
1752  parse_info.set_extension(extension);
1753  parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile);
1754 
1755  parse_info.set_language_mode(
1756  stricter_language_mode(parse_info.language_mode(), language_mode));
1757  maybe_result = CompileToplevel(&parse_info, isolate);
1758  Handle<SharedFunctionInfo> result;
1759  if (extension == nullptr && maybe_result.ToHandle(&result)) {
1760  DCHECK(result->is_compiled());
1761  compilation_cache->PutScript(source, isolate->native_context(),
1762  language_mode, result);
1763  } else if (maybe_result.is_null() && natives != EXTENSION_CODE &&
1764  natives != NATIVES_CODE) {
1765  isolate->ReportPendingMessages();
1766  }
1767  }
1768 
1769  return maybe_result;
1770 }
1771 
1772 MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
1773  Handle<String> source, Handle<FixedArray> arguments,
1774  Handle<Context> context, const Compiler::ScriptDetails& script_details,
1775  ScriptOriginOptions origin_options, ScriptData* cached_data,
1776  v8::ScriptCompiler::CompileOptions compile_options,
1777  v8::ScriptCompiler::NoCacheReason no_cache_reason) {
1778  Isolate* isolate = context->GetIsolate();
1779  ScriptCompileTimerScope compile_timer(isolate, no_cache_reason);
1780 
1781  if (compile_options == ScriptCompiler::kNoCompileOptions ||
1782  compile_options == ScriptCompiler::kEagerCompile) {
1783  DCHECK_NULL(cached_data);
1784  } else {
1785  DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache);
1786  DCHECK(cached_data);
1787  }
1788 
1789  int source_length = source->length();
1790  isolate->counters()->total_compile_size()->Increment(source_length);
1791 
1792  LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
1793 
1794  MaybeHandle<SharedFunctionInfo> maybe_result;
1795  bool can_consume_code_cache =
1796  compile_options == ScriptCompiler::kConsumeCodeCache;
1797  if (can_consume_code_cache) {
1798  compile_timer.set_consuming_code_cache();
1799  // Then check cached code provided by embedder.
1800  HistogramTimerScope timer(isolate->counters()->compile_deserialize());
1801  RuntimeCallTimerScope runtimeTimer(
1802  isolate, RuntimeCallCounterId::kCompileDeserialize);
1803  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1804  "V8.CompileDeserialize");
1805  maybe_result = CodeSerializer::Deserialize(isolate, cached_data, source,
1806  origin_options);
1807  if (maybe_result.is_null()) {
1808  // Deserializer failed. Fall through to compile.
1809  compile_timer.set_consuming_code_cache_failed();
1810  }
1811  }
1812 
1813  Handle<SharedFunctionInfo> wrapped;
1814  Handle<Script> script;
1815  if (!maybe_result.ToHandle(&wrapped)) {
1816  ParseInfo parse_info(isolate);
1817  script = NewScript(isolate, &parse_info, source, script_details,
1818  origin_options, NOT_NATIVES_CODE);
1819  script->set_wrapped_arguments(*arguments);
1820 
1821  parse_info.set_eval(); // Use an eval scope as declaration scope.
1822  parse_info.set_wrapped_as_function();
1823  // parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile);
1824  if (!context->IsNativeContext()) {
1825  parse_info.set_outer_scope_info(handle(context->scope_info(), isolate));
1826  }
1827  parse_info.set_language_mode(
1828  stricter_language_mode(parse_info.language_mode(), language_mode));
1829 
1830  Handle<SharedFunctionInfo> top_level;
1831  maybe_result = CompileToplevel(&parse_info, isolate);
1832  if (maybe_result.is_null()) isolate->ReportPendingMessages();
1833  ASSIGN_RETURN_ON_EXCEPTION(isolate, top_level, maybe_result, JSFunction);
1834 
1835  SharedFunctionInfo::ScriptIterator infos(isolate, *script);
1836  while (SharedFunctionInfo* info = infos.Next()) {
1837  if (info->is_wrapped()) {
1838  wrapped = Handle<SharedFunctionInfo>(info, isolate);
1839  break;
1840  }
1841  }
1842  DCHECK(!wrapped.is_null());
1843  } else {
1844  script = Handle<Script>(Script::cast(wrapped->script()), isolate);
1845  }
1846 
1847  return isolate->factory()->NewFunctionFromSharedFunctionInfo(wrapped, context,
1848  NOT_TENURED);
1849 }
1850 
1851 MaybeHandle<SharedFunctionInfo>
1852 Compiler::GetSharedFunctionInfoForStreamedScript(
1853  Isolate* isolate, Handle<String> source,
1854  const ScriptDetails& script_details, ScriptOriginOptions origin_options,
1855  ScriptStreamingData* streaming_data) {
1856  ScriptCompileTimerScope compile_timer(
1857  isolate, ScriptCompiler::kNoCacheBecauseStreamingSource);
1858  PostponeInterruptsScope postpone(isolate);
1859 
1860  int source_length = source->length();
1861  isolate->counters()->total_load_size()->Increment(source_length);
1862  isolate->counters()->total_compile_size()->Increment(source_length);
1863 
1864  BackgroundCompileTask* task = streaming_data->task.get();
1865  ParseInfo* parse_info = task->info();
1866  DCHECK(parse_info->is_toplevel());
1867  // Check if compile cache already holds the SFI, if so no need to finalize
1868  // the code compiled on the background thread.
1869  CompilationCache* compilation_cache = isolate->compilation_cache();
1870  MaybeHandle<SharedFunctionInfo> maybe_result =
1871  compilation_cache->LookupScript(
1872  source, script_details.name_obj, script_details.line_offset,
1873  script_details.column_offset, origin_options,
1874  isolate->native_context(), parse_info->language_mode());
1875  if (!maybe_result.is_null()) {
1876  compile_timer.set_hit_isolate_cache();
1877  }
1878 
1879  if (maybe_result.is_null()) {
1880  // No cache entry found, finalize compilation of the script and add it to
1881  // the isolate cache.
1882  Handle<Script> script =
1883  NewScript(isolate, parse_info, source, script_details, origin_options,
1884  NOT_NATIVES_CODE);
1885  task->parser()->UpdateStatistics(isolate, script);
1886  task->parser()->HandleSourceURLComments(isolate, script);
1887 
1888  if (parse_info->literal() == nullptr || !task->outer_function_job()) {
1889  // Parsing has failed - report error messages.
1890  FailWithPendingException(isolate, parse_info,
1891  Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
1892  } else {
1893  // Parsing has succeeded - finalize compilation.
1894  maybe_result =
1895  FinalizeTopLevel(parse_info, isolate, task->outer_function_job(),
1896  task->inner_function_jobs());
1897  if (maybe_result.is_null()) {
1898  // Finalization failed - throw an exception.
1899  FailWithPendingException(isolate, parse_info,
1900  Compiler::ClearExceptionFlag::KEEP_EXCEPTION);
1901  }
1902  }
1903 
1904  // Add compiled code to the isolate cache.
1905  Handle<SharedFunctionInfo> result;
1906  if (maybe_result.ToHandle(&result)) {
1907  compilation_cache->PutScript(source, isolate->native_context(),
1908  parse_info->language_mode(), result);
1909  }
1910  }
1911 
1912  streaming_data->Release();
1913  return maybe_result;
1914 }
1915 
1916 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
1917  FunctionLiteral* literal, Handle<Script> script, Isolate* isolate) {
1918  // Precondition: code has been parsed and scopes have been analyzed.
1919  MaybeHandle<SharedFunctionInfo> maybe_existing;
1920 
1921  // Find any previously allocated shared function info for the given literal.
1922  maybe_existing = script->FindSharedFunctionInfo(isolate, literal);
1923 
1924  // If we found an existing shared function info, return it.
1925  Handle<SharedFunctionInfo> existing;
1926  if (maybe_existing.ToHandle(&existing)) return existing;
1927 
1928  // Allocate a shared function info object which will be compiled lazily.
1929  Handle<SharedFunctionInfo> result =
1930  isolate->factory()->NewSharedFunctionInfoForLiteral(literal, script,
1931  false);
1932  return result;
1933 }
1934 
1935 MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function,
1936  BailoutId osr_offset,
1937  JavaScriptFrame* osr_frame) {
1938  DCHECK(!osr_offset.IsNone());
1939  DCHECK_NOT_NULL(osr_frame);
1940  return GetOptimizedCode(function, ConcurrencyMode::kNotConcurrent, osr_offset,
1941  osr_frame);
1942 }
1943 
1944 bool Compiler::FinalizeOptimizedCompilationJob(OptimizedCompilationJob* job,
1945  Isolate* isolate) {
1946  VMState<COMPILER> state(isolate);
1947  // Take ownership of compilation job. Deleting job also tears down the zone.
1948  std::unique_ptr<OptimizedCompilationJob> job_scope(job);
1949  OptimizedCompilationInfo* compilation_info = job->compilation_info();
1950 
1951  TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
1952  RuntimeCallTimerScope runtimeTimer(
1953  isolate, RuntimeCallCounterId::kRecompileSynchronous);
1954  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1955  "V8.RecompileSynchronous");
1956 
1957  Handle<SharedFunctionInfo> shared = compilation_info->shared_info();
1958 
1959  // Reset profiler ticks, function is no longer considered hot.
1960  compilation_info->closure()->feedback_vector()->set_profiler_ticks(0);
1961 
1962  DCHECK(!shared->HasBreakInfo());
1963 
1964  // 1) Optimization on the concurrent thread may have failed.
1965  // 2) The function may have already been optimized by OSR. Simply continue.
1966  // Except when OSR already disabled optimization for some reason.
1967  // 3) The code may have already been invalidated due to dependency change.
1968  // 4) Code generation may have failed.
1969  if (job->state() == CompilationJob::State::kReadyToFinalize) {
1970  if (shared->optimization_disabled()) {
1971  job->RetryOptimization(BailoutReason::kOptimizationDisabled);
1972  } else if (job->FinalizeJob(isolate) == CompilationJob::SUCCEEDED) {
1973  job->RecordCompilationStats();
1974  job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG,
1975  isolate);
1976  InsertCodeIntoOptimizedCodeCache(compilation_info);
1977  if (FLAG_trace_opt) {
1978  PrintF("[completed optimizing ");
1979  compilation_info->closure()->ShortPrint();
1980  PrintF("]\n");
1981  }
1982  compilation_info->closure()->set_code(*compilation_info->code());
1983  return CompilationJob::SUCCEEDED;
1984  }
1985  }
1986 
1987  DCHECK_EQ(job->state(), CompilationJob::State::kFailed);
1988  if (FLAG_trace_opt) {
1989  PrintF("[aborted optimizing ");
1990  compilation_info->closure()->ShortPrint();
1991  PrintF(" because: %s]\n",
1992  GetBailoutReason(compilation_info->bailout_reason()));
1993  }
1994  compilation_info->closure()->set_code(shared->GetCode());
1995  // Clear the InOptimizationQueue marker, if it exists.
1996  if (compilation_info->closure()->IsInOptimizationQueue()) {
1997  compilation_info->closure()->ClearOptimizationMarker();
1998  }
1999  return CompilationJob::FAILED;
2000 }
2001 
2002 void Compiler::PostInstantiation(Handle<JSFunction> function,
2003  PretenureFlag pretenure) {
2004  Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate());
2005 
2006  if (FLAG_always_opt && shared->allows_lazy_compilation() &&
2007  !shared->optimization_disabled() && !shared->HasAsmWasmData() &&
2008  shared->is_compiled()) {
2009  JSFunction::EnsureFeedbackVector(function);
2010 
2011  if (!function->IsOptimized()) {
2012  // Only mark for optimization if we don't already have optimized code.
2013  if (!function->HasOptimizedCode()) {
2014  function->MarkForOptimization(ConcurrencyMode::kNotConcurrent);
2015  }
2016  }
2017  }
2018 
2019  if (shared->is_compiled() && !shared->HasAsmWasmData()) {
2020  JSFunction::EnsureFeedbackVector(function);
2021 
2022  Code code = function->has_feedback_vector()
2023  ? function->feedback_vector()->optimized_code()
2024  : Code();
2025  if (!code.is_null()) {
2026  // Caching of optimized code enabled and optimized code found.
2027  DCHECK(!code->marked_for_deoptimization());
2028  DCHECK(function->shared()->is_compiled());
2029  function->set_code(code);
2030  }
2031  }
2032 
2033  if (shared->is_toplevel() || shared->is_wrapped()) {
2034  // If it's a top-level script, report compilation to the debugger.
2035  Handle<Script> script(
2036  handle(Script::cast(shared->script()), function->GetIsolate()));
2037  function->GetIsolate()->debug()->OnAfterCompile(script);
2038  }
2039 }
2040 
2041 // ----------------------------------------------------------------------------
2042 // Implementation of ScriptStreamingData
2043 
2044 ScriptStreamingData::ScriptStreamingData(
2045  ScriptCompiler::ExternalSourceStream* source_stream,
2046  ScriptCompiler::StreamedSource::Encoding encoding)
2047  : source_stream(source_stream), encoding(encoding) {}
2048 
2049 ScriptStreamingData::~ScriptStreamingData() = default;
2050 
2051 void ScriptStreamingData::Release() { task.reset(); }
2052 
2053 } // namespace internal
2054 } // namespace v8
Definition: libplatform.h:13