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