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