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