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/asmjs/asm-js.h"
11 #include "src/asmjs/asm-typer.h"
12 #include "src/ast/ast-numbering.h"
13 #include "src/ast/prettyprinter.h"
14 #include "src/ast/scopes.h"
15 #include "src/bootstrapper.h"
16 #include "src/codegen.h"
17 #include "src/compilation-cache.h"
18 #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
19 #include "src/compiler/pipeline.h"
20 #include "src/crankshaft/hydrogen.h"
21 #include "src/debug/debug.h"
22 #include "src/debug/liveedit.h"
23 #include "src/frames-inl.h"
24 #include "src/full-codegen/full-codegen.h"
25 #include "src/globals.h"
26 #include "src/heap/heap.h"
27 #include "src/interpreter/interpreter.h"
28 #include "src/isolate-inl.h"
29 #include "src/log-inl.h"
30 #include "src/messages.h"
31 #include "src/parsing/parser.h"
32 #include "src/parsing/rewriter.h"
33 #include "src/parsing/scanner-character-streams.h"
34 #include "src/runtime-profiler.h"
35 #include "src/snapshot/code-serializer.h"
36 #include "src/vm-state-inl.h"
37
38 namespace v8 {
39 namespace internal {
40
41
42
43 // A wrapper around a CompilationInfo that detaches the Handles from
44 // the underlying DeferredHandleScope and stores them in info_ on
45 // destruction.
46 class CompilationHandleScope final {
47 public:
CompilationHandleScope(CompilationInfo * info)48 explicit CompilationHandleScope(CompilationInfo* info)
49 : deferred_(info->isolate()), info_(info) {}
~CompilationHandleScope()50 ~CompilationHandleScope() { info_->set_deferred_handles(deferred_.Detach()); }
51
52 private:
53 DeferredHandleScope deferred_;
54 CompilationInfo* info_;
55 };
56
57 // Helper that times a scoped region and records the elapsed time.
58 struct ScopedTimer {
ScopedTimerv8::internal::ScopedTimer59 explicit ScopedTimer(base::TimeDelta* location) : location_(location) {
60 DCHECK(location_ != NULL);
61 timer_.Start();
62 }
63
~ScopedTimerv8::internal::ScopedTimer64 ~ScopedTimer() { *location_ += timer_.Elapsed(); }
65
66 base::ElapsedTimer timer_;
67 base::TimeDelta* location_;
68 };
69
70 // ----------------------------------------------------------------------------
71 // Implementation of CompilationJob
72
PrepareJob()73 CompilationJob::Status CompilationJob::PrepareJob() {
74 DCHECK(ThreadId::Current().Equals(info()->isolate()->thread_id()));
75 DisallowJavascriptExecution no_js(isolate());
76
77 if (FLAG_trace_opt && info()->IsOptimizing()) {
78 OFStream os(stdout);
79 os << "[compiling method " << Brief(*info()->closure()) << " using "
80 << compiler_name_;
81 if (info()->is_osr()) os << " OSR";
82 os << "]" << std::endl;
83 }
84
85 // Delegate to the underlying implementation.
86 DCHECK(state() == State::kReadyToPrepare);
87 ScopedTimer t(&time_taken_to_prepare_);
88 return UpdateState(PrepareJobImpl(), State::kReadyToExecute);
89 }
90
ExecuteJob()91 CompilationJob::Status CompilationJob::ExecuteJob() {
92 std::unique_ptr<DisallowHeapAllocation> no_allocation;
93 std::unique_ptr<DisallowHandleAllocation> no_handles;
94 std::unique_ptr<DisallowHandleDereference> no_deref;
95 std::unique_ptr<DisallowCodeDependencyChange> no_dependency_change;
96 if (can_execute_on_background_thread()) {
97 no_allocation.reset(new DisallowHeapAllocation());
98 no_handles.reset(new DisallowHandleAllocation());
99 no_deref.reset(new DisallowHandleDereference());
100 no_dependency_change.reset(new DisallowCodeDependencyChange());
101 } else {
102 DCHECK(ThreadId::Current().Equals(info()->isolate()->thread_id()));
103 }
104
105 // Delegate to the underlying implementation.
106 DCHECK(state() == State::kReadyToExecute);
107 ScopedTimer t(&time_taken_to_execute_);
108 return UpdateState(ExecuteJobImpl(), State::kReadyToFinalize);
109 }
110
FinalizeJob()111 CompilationJob::Status CompilationJob::FinalizeJob() {
112 DCHECK(ThreadId::Current().Equals(info()->isolate()->thread_id()));
113 DisallowCodeDependencyChange no_dependency_change;
114 DisallowJavascriptExecution no_js(isolate());
115 DCHECK(!info()->dependencies()->HasAborted());
116
117 // Delegate to the underlying implementation.
118 DCHECK(state() == State::kReadyToFinalize);
119 ScopedTimer t(&time_taken_to_finalize_);
120 return UpdateState(FinalizeJobImpl(), State::kSucceeded);
121 }
122
RetryOptimization(BailoutReason reason)123 CompilationJob::Status CompilationJob::RetryOptimization(BailoutReason reason) {
124 DCHECK(info_->IsOptimizing());
125 info_->RetryOptimization(reason);
126 state_ = State::kFailed;
127 return FAILED;
128 }
129
AbortOptimization(BailoutReason reason)130 CompilationJob::Status CompilationJob::AbortOptimization(BailoutReason reason) {
131 DCHECK(info_->IsOptimizing());
132 info_->AbortOptimization(reason);
133 state_ = State::kFailed;
134 return FAILED;
135 }
136
RecordUnoptimizedCompilationStats() const137 void CompilationJob::RecordUnoptimizedCompilationStats() const {
138 int code_size;
139 if (info()->has_bytecode_array()) {
140 code_size = info()->bytecode_array()->SizeIncludingMetadata();
141 } else {
142 code_size = info()->code()->SizeIncludingMetadata();
143 }
144
145 Counters* counters = isolate()->counters();
146 // TODO(4280): Rename counters from "baseline" to "unoptimized" eventually.
147 counters->total_baseline_code_size()->Increment(code_size);
148 counters->total_baseline_compile_count()->Increment(1);
149
150 // TODO(5203): Add timers for each phase of compilation.
151 }
152
RecordOptimizedCompilationStats() const153 void CompilationJob::RecordOptimizedCompilationStats() const {
154 DCHECK(info()->IsOptimizing());
155 Handle<JSFunction> function = info()->closure();
156 if (!function->IsOptimized()) {
157 // Concurrent recompilation and OSR may race. Increment only once.
158 int opt_count = function->shared()->opt_count();
159 function->shared()->set_opt_count(opt_count + 1);
160 }
161 double ms_creategraph = time_taken_to_prepare_.InMillisecondsF();
162 double ms_optimize = time_taken_to_execute_.InMillisecondsF();
163 double ms_codegen = time_taken_to_finalize_.InMillisecondsF();
164 if (FLAG_trace_opt) {
165 PrintF("[optimizing ");
166 function->ShortPrint();
167 PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize,
168 ms_codegen);
169 }
170 if (FLAG_trace_opt_stats) {
171 static double compilation_time = 0.0;
172 static int compiled_functions = 0;
173 static int code_size = 0;
174
175 compilation_time += (ms_creategraph + ms_optimize + ms_codegen);
176 compiled_functions++;
177 code_size += function->shared()->SourceSize();
178 PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
179 compiled_functions, code_size, compilation_time);
180 }
181 if (FLAG_hydrogen_stats) {
182 isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_prepare_,
183 time_taken_to_execute_,
184 time_taken_to_finalize_);
185 }
186 }
187
isolate() const188 Isolate* CompilationJob::isolate() const { return info()->isolate(); }
189
190 namespace {
191
AddWeakObjectToCodeDependency(Isolate * isolate,Handle<HeapObject> object,Handle<Code> code)192 void AddWeakObjectToCodeDependency(Isolate* isolate, Handle<HeapObject> object,
193 Handle<Code> code) {
194 Handle<WeakCell> cell = Code::WeakCellFor(code);
195 Heap* heap = isolate->heap();
196 if (heap->InNewSpace(*object)) {
197 heap->AddWeakNewSpaceObjectToCodeDependency(object, cell);
198 } else {
199 Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(object));
200 dep =
201 DependentCode::InsertWeakCode(dep, DependentCode::kWeakCodeGroup, cell);
202 heap->AddWeakObjectToCodeDependency(object, dep);
203 }
204 }
205
206 } // namespace
207
RegisterWeakObjectsInOptimizedCode(Handle<Code> code)208 void CompilationJob::RegisterWeakObjectsInOptimizedCode(Handle<Code> code) {
209 // TODO(turbofan): Move this to pipeline.cc once Crankshaft dies.
210 Isolate* const isolate = code->GetIsolate();
211 DCHECK(code->is_optimized_code());
212 std::vector<Handle<Map>> maps;
213 std::vector<Handle<HeapObject>> objects;
214 {
215 DisallowHeapAllocation no_gc;
216 int const mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
217 RelocInfo::ModeMask(RelocInfo::CELL);
218 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
219 RelocInfo::Mode mode = it.rinfo()->rmode();
220 if (mode == RelocInfo::CELL &&
221 code->IsWeakObjectInOptimizedCode(it.rinfo()->target_cell())) {
222 objects.push_back(handle(it.rinfo()->target_cell(), isolate));
223 } else if (mode == RelocInfo::EMBEDDED_OBJECT &&
224 code->IsWeakObjectInOptimizedCode(
225 it.rinfo()->target_object())) {
226 Handle<HeapObject> object(HeapObject::cast(it.rinfo()->target_object()),
227 isolate);
228 if (object->IsMap()) {
229 maps.push_back(Handle<Map>::cast(object));
230 } else {
231 objects.push_back(object);
232 }
233 }
234 }
235 }
236 for (Handle<Map> map : maps) {
237 if (map->dependent_code()->IsEmpty(DependentCode::kWeakCodeGroup)) {
238 isolate->heap()->AddRetainedMap(map);
239 }
240 Map::AddDependentCode(map, DependentCode::kWeakCodeGroup, code);
241 }
242 for (Handle<HeapObject> object : objects) {
243 AddWeakObjectToCodeDependency(isolate, object, code);
244 }
245 code->set_can_have_weak_objects(true);
246 }
247
248 // ----------------------------------------------------------------------------
249 // Local helper methods that make up the compilation pipeline.
250
251 namespace {
252
RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,CompilationInfo * info)253 void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
254 CompilationInfo* info) {
255 // Log the code generation. If source information is available include
256 // script name and line number. Check explicitly whether logging is
257 // enabled as finding the line number is not free.
258 if (info->isolate()->logger()->is_logging_code_events() ||
259 info->isolate()->is_profiling()) {
260 Handle<SharedFunctionInfo> shared = info->shared_info();
261 Handle<Script> script = info->parse_info()->script();
262 Handle<AbstractCode> abstract_code =
263 info->has_bytecode_array()
264 ? Handle<AbstractCode>::cast(info->bytecode_array())
265 : Handle<AbstractCode>::cast(info->code());
266 if (abstract_code.is_identical_to(
267 info->isolate()->builtins()->CompileLazy())) {
268 return;
269 }
270 int line_num = Script::GetLineNumber(script, shared->start_position()) + 1;
271 int column_num =
272 Script::GetColumnNumber(script, shared->start_position()) + 1;
273 String* script_name = script->name()->IsString()
274 ? String::cast(script->name())
275 : info->isolate()->heap()->empty_string();
276 CodeEventListener::LogEventsAndTags log_tag =
277 Logger::ToNativeByScript(tag, *script);
278 PROFILE(info->isolate(),
279 CodeCreateEvent(log_tag, *abstract_code, *shared, script_name,
280 line_num, column_num));
281 }
282 }
283
EnsureFeedbackMetadata(CompilationInfo * info)284 void EnsureFeedbackMetadata(CompilationInfo* info) {
285 DCHECK(info->has_shared_info());
286
287 // If no type feedback metadata exists, we create it now. At this point the
288 // AstNumbering pass has already run. Note the snapshot can contain outdated
289 // vectors for a different configuration, hence we also recreate a new vector
290 // when the function is not compiled (i.e. no code was serialized).
291
292 // TODO(mvstanton): reintroduce is_empty() predicate to feedback_metadata().
293 if (info->shared_info()->feedback_metadata()->length() == 0 ||
294 !info->shared_info()->is_compiled()) {
295 Handle<TypeFeedbackMetadata> feedback_metadata = TypeFeedbackMetadata::New(
296 info->isolate(), info->literal()->feedback_vector_spec());
297 info->shared_info()->set_feedback_metadata(*feedback_metadata);
298 }
299
300 // It's very important that recompiles do not alter the structure of the type
301 // feedback vector. Verify that the structure fits the function literal.
302 CHECK(!info->shared_info()->feedback_metadata()->SpecDiffersFrom(
303 info->literal()->feedback_vector_spec()));
304 }
305
UseTurboFan(Handle<SharedFunctionInfo> shared)306 bool UseTurboFan(Handle<SharedFunctionInfo> shared) {
307 bool optimization_disabled = shared->optimization_disabled();
308 bool dont_crankshaft = shared->dont_crankshaft();
309
310 // Check the enabling conditions for Turbofan.
311 // 1. "use asm" code.
312 bool is_turbofanable_asm =
313 FLAG_turbo_asm && shared->asm_function() && !optimization_disabled;
314
315 // 2. Fallback for features unsupported by Crankshaft.
316 bool is_unsupported_by_crankshaft_but_turbofanable =
317 dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0 &&
318 !optimization_disabled;
319
320 // 3. Explicitly enabled by the command-line filter.
321 bool passes_turbo_filter = shared->PassesFilter(FLAG_turbo_filter);
322
323 return is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable ||
324 passes_turbo_filter;
325 }
326
ShouldUseIgnition(CompilationInfo * info)327 bool ShouldUseIgnition(CompilationInfo* info) {
328 DCHECK(info->has_shared_info());
329
330 // Skip Ignition for asm.js functions.
331 if (info->shared_info()->asm_function()) {
332 return false;
333 }
334
335 // When requesting debug code as a replacement for existing code, we provide
336 // the same kind as the existing code (to prevent implicit tier-change).
337 if (info->is_debug() && info->shared_info()->is_compiled()) {
338 return !info->shared_info()->HasBaselineCode();
339 }
340
341 // Code destined for TurboFan should be compiled with Ignition first.
342 if (UseTurboFan(info->shared_info())) return true;
343
344 // Only use Ignition for any other function if FLAG_ignition is true.
345 if (!FLAG_ignition) return false;
346
347 // Checks whether top level functions should be passed by the filter.
348 if (info->shared_info()->is_toplevel()) {
349 Vector<const char> filter = CStrVector(FLAG_ignition_filter);
350 return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*');
351 }
352
353 // Finally respect the filter.
354 return info->shared_info()->PassesFilter(FLAG_ignition_filter);
355 }
356
GetUnoptimizedCompilationJob(CompilationInfo * info)357 CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) {
358 // Function should have been parsed and analyzed before creating a compilation
359 // job.
360 DCHECK_NOT_NULL(info->literal());
361 DCHECK_NOT_NULL(info->scope());
362
363 EnsureFeedbackMetadata(info);
364 if (ShouldUseIgnition(info)) {
365 return interpreter::Interpreter::NewCompilationJob(info);
366 } else {
367 return FullCodeGenerator::NewCompilationJob(info);
368 }
369 }
370
InstallSharedScopeInfo(CompilationInfo * info,Handle<SharedFunctionInfo> shared)371 void InstallSharedScopeInfo(CompilationInfo* info,
372 Handle<SharedFunctionInfo> shared) {
373 Handle<ScopeInfo> scope_info = info->scope()->scope_info();
374 shared->set_scope_info(*scope_info);
375 Scope* outer_scope = info->scope()->GetOuterScopeWithContext();
376 if (outer_scope) {
377 shared->set_outer_scope_info(*outer_scope->scope_info());
378 }
379 }
380
InstallSharedCompilationResult(CompilationInfo * info,Handle<SharedFunctionInfo> shared)381 void InstallSharedCompilationResult(CompilationInfo* info,
382 Handle<SharedFunctionInfo> shared) {
383 // TODO(mstarzinger): Compiling for debug code might be used to reveal inner
384 // functions via {FindSharedFunctionInfoInScript}, in which case we end up
385 // regenerating existing bytecode. Fix this!
386 if (info->is_debug() && info->has_bytecode_array()) {
387 shared->ClearBytecodeArray();
388 }
389 DCHECK(!info->code().is_null());
390 shared->ReplaceCode(*info->code());
391 if (info->has_bytecode_array()) {
392 DCHECK(!shared->HasBytecodeArray()); // Only compiled once.
393 shared->set_bytecode_array(*info->bytecode_array());
394 }
395 }
396
InstallUnoptimizedCode(CompilationInfo * info)397 void InstallUnoptimizedCode(CompilationInfo* info) {
398 Handle<SharedFunctionInfo> shared = info->shared_info();
399
400 // Update the shared function info with the scope info.
401 InstallSharedScopeInfo(info, shared);
402
403 // Install compilation result on the shared function info
404 InstallSharedCompilationResult(info, shared);
405 }
406
FinalizeUnoptimizedCompilationJob(CompilationJob * job)407 CompilationJob::Status FinalizeUnoptimizedCompilationJob(CompilationJob* job) {
408 CompilationJob::Status status = job->FinalizeJob();
409 if (status == CompilationJob::SUCCEEDED) {
410 InstallUnoptimizedCode(job->info());
411 job->RecordUnoptimizedCompilationStats();
412 }
413 return status;
414 }
415
GenerateUnoptimizedCode(CompilationInfo * info)416 bool GenerateUnoptimizedCode(CompilationInfo* info) {
417 if (FLAG_validate_asm && info->scope()->asm_module() &&
418 !info->shared_info()->is_asm_wasm_broken() && !info->is_debug()) {
419 EnsureFeedbackMetadata(info);
420 MaybeHandle<FixedArray> wasm_data;
421 wasm_data = AsmJs::ConvertAsmToWasm(info->parse_info());
422 if (!wasm_data.is_null()) {
423 info->shared_info()->set_asm_wasm_data(*wasm_data.ToHandleChecked());
424 info->SetCode(info->isolate()->builtins()->InstantiateAsmJs());
425 InstallUnoptimizedCode(info);
426 return true;
427 }
428 }
429
430 std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info));
431 if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false;
432 if (job->ExecuteJob() != CompilationJob::SUCCEEDED) return false;
433 if (FinalizeUnoptimizedCompilationJob(job.get()) !=
434 CompilationJob::SUCCEEDED) {
435 return false;
436 }
437 return true;
438 }
439
CompileUnoptimizedCode(CompilationInfo * info)440 bool CompileUnoptimizedCode(CompilationInfo* info) {
441 DCHECK(AllowCompilation::IsAllowed(info->isolate()));
442 if (!Compiler::Analyze(info->parse_info()) ||
443 !GenerateUnoptimizedCode(info)) {
444 Isolate* isolate = info->isolate();
445 if (!isolate->has_pending_exception()) isolate->StackOverflow();
446 return false;
447 }
448 return true;
449 }
450
GetUnoptimizedCode(CompilationInfo * info)451 MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) {
452 VMState<COMPILER> state(info->isolate());
453 PostponeInterruptsScope postpone(info->isolate());
454
455 // Parse and update CompilationInfo with the results.
456 if (!Parser::ParseStatic(info->parse_info())) return MaybeHandle<Code>();
457 DCHECK_EQ(info->shared_info()->language_mode(),
458 info->literal()->language_mode());
459
460 // Compile either unoptimized code or bytecode for the interpreter.
461 if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>();
462
463 // Record the function compilation event.
464 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, info);
465
466 return info->code();
467 }
468
GetCodeFromOptimizedCodeMap(Handle<JSFunction> function,BailoutId osr_ast_id)469 MUST_USE_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeMap(
470 Handle<JSFunction> function, BailoutId osr_ast_id) {
471 Handle<SharedFunctionInfo> shared(function->shared());
472 DisallowHeapAllocation no_gc;
473 CodeAndLiterals cached = shared->SearchOptimizedCodeMap(
474 function->context()->native_context(), osr_ast_id);
475 if (cached.code != nullptr) {
476 // Caching of optimized code enabled and optimized code found.
477 if (cached.literals != nullptr) function->set_literals(cached.literals);
478 DCHECK(!cached.code->marked_for_deoptimization());
479 DCHECK(function->shared()->is_compiled());
480 return Handle<Code>(cached.code);
481 }
482 return MaybeHandle<Code>();
483 }
484
InsertCodeIntoOptimizedCodeMap(CompilationInfo * info)485 void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
486 Handle<Code> code = info->code();
487 if (code->kind() != Code::OPTIMIZED_FUNCTION) return; // Nothing to do.
488
489 // Function context specialization folds-in the function context,
490 // so no sharing can occur.
491 if (info->is_function_context_specializing()) return;
492 // Frame specialization implies function context specialization.
493 DCHECK(!info->is_frame_specializing());
494
495 // TODO(4764): When compiling for OSR from bytecode, BailoutId might derive
496 // from bytecode offset and overlap with actual BailoutId. No caching!
497 if (info->is_osr() && info->is_optimizing_from_bytecode()) return;
498
499 // Cache optimized context-specific code.
500 Handle<JSFunction> function = info->closure();
501 Handle<SharedFunctionInfo> shared(function->shared());
502 Handle<LiteralsArray> literals(function->literals());
503 Handle<Context> native_context(function->context()->native_context());
504 SharedFunctionInfo::AddToOptimizedCodeMap(shared, native_context, code,
505 literals, info->osr_ast_id());
506 }
507
Renumber(ParseInfo * parse_info)508 bool Renumber(ParseInfo* parse_info) {
509 if (!AstNumbering::Renumber(parse_info->isolate(), parse_info->zone(),
510 parse_info->literal())) {
511 return false;
512 }
513 Handle<SharedFunctionInfo> shared_info = parse_info->shared_info();
514 if (!shared_info.is_null()) {
515 FunctionLiteral* lit = parse_info->literal();
516 shared_info->set_ast_node_count(lit->ast_node_count());
517 if (lit->dont_optimize_reason() != kNoReason) {
518 shared_info->DisableOptimization(lit->dont_optimize_reason());
519 }
520 if (lit->flags() & AstProperties::kDontCrankshaft) {
521 shared_info->set_dont_crankshaft(true);
522 }
523 }
524 return true;
525 }
526
GetOptimizedCodeNow(CompilationJob * job)527 bool GetOptimizedCodeNow(CompilationJob* job) {
528 CompilationInfo* info = job->info();
529 Isolate* isolate = info->isolate();
530
531 // Parsing is not required when optimizing from existing bytecode.
532 if (!info->is_optimizing_from_bytecode()) {
533 if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;
534 EnsureFeedbackMetadata(info);
535 }
536
537 JSFunction::EnsureLiterals(info->closure());
538
539 TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
540 RuntimeCallTimerScope runtimeTimer(isolate,
541 &RuntimeCallStats::RecompileSynchronous);
542 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
543 "V8.RecompileSynchronous");
544
545 if (job->PrepareJob() != CompilationJob::SUCCEEDED ||
546 job->ExecuteJob() != CompilationJob::SUCCEEDED ||
547 job->FinalizeJob() != CompilationJob::SUCCEEDED) {
548 if (FLAG_trace_opt) {
549 PrintF("[aborted optimizing ");
550 info->closure()->ShortPrint();
551 PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason()));
552 }
553 return false;
554 }
555
556 // Success!
557 job->RecordOptimizedCompilationStats();
558 DCHECK(!isolate->has_pending_exception());
559 InsertCodeIntoOptimizedCodeMap(info);
560 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, info);
561 return true;
562 }
563
GetOptimizedCodeLater(CompilationJob * job)564 bool GetOptimizedCodeLater(CompilationJob* job) {
565 CompilationInfo* info = job->info();
566 Isolate* isolate = info->isolate();
567
568 if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) {
569 if (FLAG_trace_concurrent_recompilation) {
570 PrintF(" ** Compilation queue full, will retry optimizing ");
571 info->closure()->ShortPrint();
572 PrintF(" later.\n");
573 }
574 return false;
575 }
576
577 if (isolate->heap()->HighMemoryPressure()) {
578 if (FLAG_trace_concurrent_recompilation) {
579 PrintF(" ** High memory pressure, will retry optimizing ");
580 info->closure()->ShortPrint();
581 PrintF(" later.\n");
582 }
583 return false;
584 }
585
586 // Parsing is not required when optimizing from existing bytecode.
587 if (!info->is_optimizing_from_bytecode()) {
588 if (!Compiler::ParseAndAnalyze(info->parse_info())) return false;
589 EnsureFeedbackMetadata(info);
590 }
591
592 JSFunction::EnsureLiterals(info->closure());
593
594 TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());
595 RuntimeCallTimerScope runtimeTimer(info->isolate(),
596 &RuntimeCallStats::RecompileSynchronous);
597 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
598 "V8.RecompileSynchronous");
599
600 if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false;
601 isolate->optimizing_compile_dispatcher()->QueueForOptimization(job);
602
603 if (FLAG_trace_concurrent_recompilation) {
604 PrintF(" ** Queued ");
605 info->closure()->ShortPrint();
606 PrintF(" for concurrent optimization.\n");
607 }
608 return true;
609 }
610
GetOptimizedCode(Handle<JSFunction> function,Compiler::ConcurrencyMode mode,BailoutId osr_ast_id=BailoutId::None (),JavaScriptFrame * osr_frame=nullptr)611 MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
612 Compiler::ConcurrencyMode mode,
613 BailoutId osr_ast_id = BailoutId::None(),
614 JavaScriptFrame* osr_frame = nullptr) {
615 Isolate* isolate = function->GetIsolate();
616 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
617
618 bool ignition_osr = osr_frame && osr_frame->is_interpreted();
619 DCHECK_IMPLIES(ignition_osr, !osr_ast_id.IsNone());
620 DCHECK_IMPLIES(ignition_osr, FLAG_ignition_osr);
621
622 // Shared function no longer needs to be tiered up
623 shared->set_marked_for_tier_up(false);
624
625 Handle<Code> cached_code;
626 // TODO(4764): When compiling for OSR from bytecode, BailoutId might derive
627 // from bytecode offset and overlap with actual BailoutId. No lookup!
628 if (!ignition_osr &&
629 GetCodeFromOptimizedCodeMap(function, osr_ast_id)
630 .ToHandle(&cached_code)) {
631 if (FLAG_trace_opt) {
632 PrintF("[found optimized code for ");
633 function->ShortPrint();
634 if (!osr_ast_id.IsNone()) {
635 PrintF(" at OSR AST id %d", osr_ast_id.ToInt());
636 }
637 PrintF("]\n");
638 }
639 return cached_code;
640 }
641
642 // Reset profiler ticks, function is no longer considered hot.
643 if (shared->HasBaselineCode()) {
644 shared->code()->set_profiler_ticks(0);
645 } else if (shared->HasBytecodeArray()) {
646 shared->set_profiler_ticks(0);
647 }
648
649 VMState<COMPILER> state(isolate);
650 DCHECK(!isolate->has_pending_exception());
651 PostponeInterruptsScope postpone(isolate);
652 bool use_turbofan = UseTurboFan(shared) || ignition_osr;
653 std::unique_ptr<CompilationJob> job(
654 use_turbofan ? compiler::Pipeline::NewCompilationJob(function)
655 : new HCompilationJob(function));
656 CompilationInfo* info = job->info();
657 ParseInfo* parse_info = info->parse_info();
658
659 info->SetOptimizingForOsr(osr_ast_id, osr_frame);
660
661 // Do not use Crankshaft/TurboFan if we need to be able to set break points.
662 if (info->shared_info()->HasDebugInfo()) {
663 info->AbortOptimization(kFunctionBeingDebugged);
664 return MaybeHandle<Code>();
665 }
666
667 // Limit the number of times we try to optimize functions.
668 const int kMaxOptCount =
669 FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000;
670 if (info->shared_info()->opt_count() > kMaxOptCount) {
671 info->AbortOptimization(kOptimizedTooManyTimes);
672 return MaybeHandle<Code>();
673 }
674
675 TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate);
676 RuntimeCallTimerScope runtimeTimer(isolate, &RuntimeCallStats::OptimizeCode);
677 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.OptimizeCode");
678
679 // TurboFan can optimize directly from existing bytecode.
680 if (use_turbofan && ShouldUseIgnition(info)) {
681 if (info->is_osr() && !ignition_osr) return MaybeHandle<Code>();
682 if (!Compiler::EnsureBytecode(info)) {
683 if (isolate->has_pending_exception()) isolate->clear_pending_exception();
684 return MaybeHandle<Code>();
685 }
686 info->MarkAsOptimizeFromBytecode();
687 }
688
689 // Verify that OSR compilations are delegated to the correct graph builder.
690 // Depending on the underlying frame the semantics of the {BailoutId} differ
691 // and the various graph builders hard-code a certain semantic:
692 // - Interpreter : The BailoutId represents a bytecode offset.
693 // - FullCodegen : The BailoutId represents the id of an AST node.
694 DCHECK_IMPLIES(info->is_osr() && ignition_osr,
695 info->is_optimizing_from_bytecode());
696 DCHECK_IMPLIES(info->is_osr() && !ignition_osr,
697 !info->is_optimizing_from_bytecode());
698
699 // In case of concurrent recompilation, all handles below this point will be
700 // allocated in a deferred handle scope that is detached and handed off to
701 // the background thread when we return.
702 std::unique_ptr<CompilationHandleScope> compilation;
703 if (mode == Compiler::CONCURRENT) {
704 compilation.reset(new CompilationHandleScope(info));
705 }
706
707 // In case of TurboFan, all handles below will be canonicalized.
708 std::unique_ptr<CanonicalHandleScope> canonical;
709 if (use_turbofan) canonical.reset(new CanonicalHandleScope(info->isolate()));
710
711 // Reopen handles in the new CompilationHandleScope.
712 info->ReopenHandlesInNewHandleScope();
713 parse_info->ReopenHandlesInNewHandleScope();
714
715 if (mode == Compiler::CONCURRENT) {
716 if (GetOptimizedCodeLater(job.get())) {
717 job.release(); // The background recompile job owns this now.
718 return isolate->builtins()->InOptimizationQueue();
719 }
720 } else {
721 if (GetOptimizedCodeNow(job.get())) return info->code();
722 }
723
724 if (isolate->has_pending_exception()) isolate->clear_pending_exception();
725 return MaybeHandle<Code>();
726 }
727
FinalizeOptimizedCompilationJob(CompilationJob * job)728 CompilationJob::Status FinalizeOptimizedCompilationJob(CompilationJob* job) {
729 CompilationInfo* info = job->info();
730 Isolate* isolate = info->isolate();
731
732 TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());
733 RuntimeCallTimerScope runtimeTimer(isolate,
734 &RuntimeCallStats::RecompileSynchronous);
735 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
736 "V8.RecompileSynchronous");
737
738 Handle<SharedFunctionInfo> shared = info->shared_info();
739
740 // Reset profiler ticks, function is no longer considered hot.
741 if (shared->HasBaselineCode()) {
742 shared->code()->set_profiler_ticks(0);
743 } else if (shared->HasBytecodeArray()) {
744 shared->set_profiler_ticks(0);
745 }
746
747 DCHECK(!shared->HasDebugInfo());
748
749 // 1) Optimization on the concurrent thread may have failed.
750 // 2) The function may have already been optimized by OSR. Simply continue.
751 // Except when OSR already disabled optimization for some reason.
752 // 3) The code may have already been invalidated due to dependency change.
753 // 4) Code generation may have failed.
754 if (job->state() == CompilationJob::State::kReadyToFinalize) {
755 if (shared->optimization_disabled()) {
756 job->RetryOptimization(kOptimizationDisabled);
757 } else if (info->dependencies()->HasAborted()) {
758 job->RetryOptimization(kBailedOutDueToDependencyChange);
759 } else if (job->FinalizeJob() == CompilationJob::SUCCEEDED) {
760 job->RecordOptimizedCompilationStats();
761 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, info);
762 if (shared
763 ->SearchOptimizedCodeMap(info->context()->native_context(),
764 info->osr_ast_id())
765 .code == nullptr) {
766 InsertCodeIntoOptimizedCodeMap(info);
767 }
768 if (FLAG_trace_opt) {
769 PrintF("[completed optimizing ");
770 info->closure()->ShortPrint();
771 PrintF("]\n");
772 }
773 info->closure()->ReplaceCode(*info->code());
774 return CompilationJob::SUCCEEDED;
775 }
776 }
777
778 DCHECK(job->state() == CompilationJob::State::kFailed);
779 if (FLAG_trace_opt) {
780 PrintF("[aborted optimizing ");
781 info->closure()->ShortPrint();
782 PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason()));
783 }
784 info->closure()->ReplaceCode(shared->code());
785 return CompilationJob::FAILED;
786 }
787
GetBaselineCode(Handle<JSFunction> function)788 MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) {
789 Isolate* isolate = function->GetIsolate();
790 VMState<COMPILER> state(isolate);
791 PostponeInterruptsScope postpone(isolate);
792 Zone zone(isolate->allocator(), ZONE_NAME);
793 ParseInfo parse_info(&zone, handle(function->shared()));
794 CompilationInfo info(&parse_info, function);
795
796 // Function no longer needs to be tiered up
797 function->shared()->set_marked_for_tier_up(false);
798
799 // Reset profiler ticks, function is no longer considered hot.
800 if (function->shared()->HasBytecodeArray()) {
801 function->shared()->set_profiler_ticks(0);
802 }
803
804 // Nothing left to do if the function already has baseline code.
805 if (function->shared()->code()->kind() == Code::FUNCTION) {
806 return Handle<Code>(function->shared()->code());
807 }
808
809 // We do not switch to baseline code when the debugger might have created a
810 // copy of the bytecode with break slots to be able to set break points.
811 if (function->shared()->HasDebugInfo()) {
812 return MaybeHandle<Code>();
813 }
814
815 // TODO(4280): For now we do not switch generators or async functions to
816 // baseline code because there might be suspended activations stored in
817 // generator objects on the heap. We could eventually go directly to
818 // TurboFan in this case.
819 if (IsResumableFunction(function->shared()->kind())) {
820 return MaybeHandle<Code>();
821 }
822
823 if (FLAG_trace_opt) {
824 OFStream os(stdout);
825 os << "[switching method " << Brief(*function) << " to baseline code]"
826 << std::endl;
827 }
828
829 // Parse and update CompilationInfo with the results.
830 if (!Parser::ParseStatic(info.parse_info())) return MaybeHandle<Code>();
831 Handle<SharedFunctionInfo> shared = info.shared_info();
832 DCHECK_EQ(shared->language_mode(), info.literal()->language_mode());
833
834 // Compile baseline code using the full code generator.
835 if (!Compiler::Analyze(info.parse_info()) ||
836 !FullCodeGenerator::MakeCode(&info)) {
837 if (!isolate->has_pending_exception()) isolate->StackOverflow();
838 return MaybeHandle<Code>();
839 }
840
841 // Update the shared function info with the scope info.
842 InstallSharedScopeInfo(&info, shared);
843
844 // Install compilation result on the shared function info
845 InstallSharedCompilationResult(&info, shared);
846
847 // Record the function compilation event.
848 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, &info);
849
850 return info.code();
851 }
852
GetLazyCode(Handle<JSFunction> function)853 MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) {
854 Isolate* isolate = function->GetIsolate();
855 DCHECK(!isolate->has_pending_exception());
856 DCHECK(!function->is_compiled());
857 TimerEventScope<TimerEventCompileCode> compile_timer(isolate);
858 RuntimeCallTimerScope runtimeTimer(isolate,
859 &RuntimeCallStats::CompileCodeLazy);
860 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
861 AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
862
863 Handle<Code> cached_code;
864 if (GetCodeFromOptimizedCodeMap(function, BailoutId::None())
865 .ToHandle(&cached_code)) {
866 if (FLAG_trace_opt) {
867 PrintF("[found optimized code for ");
868 function->ShortPrint();
869 PrintF(" during unoptimized compile]\n");
870 }
871 DCHECK(function->shared()->is_compiled());
872 return cached_code;
873 }
874
875 if (function->shared()->marked_for_tier_up()) {
876 DCHECK(FLAG_mark_shared_functions_for_tier_up);
877
878 function->shared()->set_marked_for_tier_up(false);
879
880 switch (Compiler::NextCompilationTier(*function)) {
881 case Compiler::BASELINE: {
882 if (FLAG_trace_opt) {
883 PrintF("[recompiling function ");
884 function->ShortPrint();
885 PrintF(
886 " to baseline eagerly (shared function marked for tier up)]\n");
887 }
888
889 Handle<Code> code;
890 if (GetBaselineCode(function).ToHandle(&code)) {
891 return code;
892 }
893 break;
894 }
895 case Compiler::OPTIMIZED: {
896 if (FLAG_trace_opt) {
897 PrintF("[optimizing method ");
898 function->ShortPrint();
899 PrintF(" eagerly (shared function marked for tier up)]\n");
900 }
901
902 Handle<Code> code;
903 // TODO(leszeks): Look into performing this compilation concurrently.
904 if (GetOptimizedCode(function, Compiler::NOT_CONCURRENT)
905 .ToHandle(&code)) {
906 return code;
907 }
908 break;
909 }
910 default:
911 UNREACHABLE();
912 }
913 }
914
915 if (function->shared()->is_compiled()) {
916 return Handle<Code>(function->shared()->code());
917 }
918
919 if (function->shared()->HasBytecodeArray()) {
920 Handle<Code> entry = isolate->builtins()->InterpreterEntryTrampoline();
921 function->shared()->ReplaceCode(*entry);
922 return entry;
923 }
924
925 Zone zone(isolate->allocator(), ZONE_NAME);
926 ParseInfo parse_info(&zone, handle(function->shared()));
927 CompilationInfo info(&parse_info, function);
928 Handle<Code> result;
929 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCode(&info), Code);
930
931 if (FLAG_always_opt) {
932 Handle<Code> opt_code;
933 if (GetOptimizedCode(function, Compiler::NOT_CONCURRENT)
934 .ToHandle(&opt_code)) {
935 result = opt_code;
936 }
937 }
938
939 return result;
940 }
941
942
NewSharedFunctionInfoForLiteral(Isolate * isolate,FunctionLiteral * literal,Handle<Script> script)943 Handle<SharedFunctionInfo> NewSharedFunctionInfoForLiteral(
944 Isolate* isolate, FunctionLiteral* literal, Handle<Script> script) {
945 Handle<Code> code = isolate->builtins()->CompileLazy();
946 Handle<ScopeInfo> scope_info = handle(ScopeInfo::Empty(isolate));
947 Handle<SharedFunctionInfo> result = isolate->factory()->NewSharedFunctionInfo(
948 literal->name(), literal->materialized_literal_count(), literal->kind(),
949 code, scope_info);
950 SharedFunctionInfo::InitFromFunctionLiteral(result, literal);
951 SharedFunctionInfo::SetScript(result, script);
952 return result;
953 }
954
CompileToplevel(CompilationInfo * info)955 Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
956 Isolate* isolate = info->isolate();
957 TimerEventScope<TimerEventCompileCode> timer(isolate);
958 RuntimeCallTimerScope runtimeTimer(isolate, &RuntimeCallStats::CompileCode);
959 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
960 PostponeInterruptsScope postpone(isolate);
961 DCHECK(!isolate->native_context().is_null());
962 ParseInfo* parse_info = info->parse_info();
963 Handle<Script> script = parse_info->script();
964
965 // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile?
966 FixedArray* array = isolate->native_context()->embedder_data();
967 script->set_context_data(array->get(v8::Context::kDebugIdIndex));
968
969 isolate->debug()->OnBeforeCompile(script);
970
971 Handle<SharedFunctionInfo> result;
972
973 { VMState<COMPILER> state(info->isolate());
974 if (parse_info->literal() == nullptr && !Parser::ParseStatic(parse_info)) {
975 return Handle<SharedFunctionInfo>::null();
976 }
977
978 FunctionLiteral* lit = parse_info->literal();
979
980 // Measure how long it takes to do the compilation; only take the
981 // rest of the function into account to avoid overlap with the
982 // parsing statistics.
983 RuntimeCallTimerScope runtimeTimer(
984 isolate, parse_info->is_eval() ? &RuntimeCallStats::CompileEval
985 : &RuntimeCallStats::Compile);
986 HistogramTimer* rate = parse_info->is_eval()
987 ? info->isolate()->counters()->compile_eval()
988 : info->isolate()->counters()->compile();
989 HistogramTimerScope timer(rate);
990 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
991 parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile");
992
993 // Allocate a shared function info object.
994 DCHECK_EQ(kNoSourcePosition, lit->function_token_position());
995 result = NewSharedFunctionInfoForLiteral(isolate, lit, script);
996 result->set_is_toplevel(true);
997 parse_info->set_shared_info(result);
998
999 // Compile the code.
1000 if (!CompileUnoptimizedCode(info)) {
1001 return Handle<SharedFunctionInfo>::null();
1002 }
1003
1004 Handle<String> script_name =
1005 script->name()->IsString()
1006 ? Handle<String>(String::cast(script->name()))
1007 : isolate->factory()->empty_string();
1008 CodeEventListener::LogEventsAndTags log_tag =
1009 parse_info->is_eval()
1010 ? CodeEventListener::EVAL_TAG
1011 : Logger::ToNativeByScript(CodeEventListener::SCRIPT_TAG, *script);
1012
1013 PROFILE(isolate, CodeCreateEvent(log_tag, result->abstract_code(), *result,
1014 *script_name));
1015
1016 if (!script.is_null())
1017 script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
1018 }
1019
1020 return result;
1021 }
1022
1023 } // namespace
1024
1025 // ----------------------------------------------------------------------------
1026 // Implementation of Compiler
1027
Analyze(ParseInfo * info)1028 bool Compiler::Analyze(ParseInfo* info) {
1029 DCHECK_NOT_NULL(info->literal());
1030 if (!Rewriter::Rewrite(info)) return false;
1031 DeclarationScope::Analyze(info, AnalyzeMode::kRegular);
1032 if (!Renumber(info)) return false;
1033 DCHECK_NOT_NULL(info->scope());
1034 return true;
1035 }
1036
ParseAndAnalyze(ParseInfo * info)1037 bool Compiler::ParseAndAnalyze(ParseInfo* info) {
1038 if (!Parser::ParseStatic(info)) return false;
1039 if (!Compiler::Analyze(info)) return false;
1040 DCHECK_NOT_NULL(info->literal());
1041 DCHECK_NOT_NULL(info->scope());
1042 return true;
1043 }
1044
Compile(Handle<JSFunction> function,ClearExceptionFlag flag)1045 bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) {
1046 if (function->is_compiled()) return true;
1047 Isolate* isolate = function->GetIsolate();
1048 DCHECK(AllowCompilation::IsAllowed(isolate));
1049
1050 // Start a compilation.
1051 Handle<Code> code;
1052 if (!GetLazyCode(function).ToHandle(&code)) {
1053 if (flag == CLEAR_EXCEPTION) {
1054 isolate->clear_pending_exception();
1055 }
1056 return false;
1057 }
1058
1059 // Install code on closure.
1060 function->ReplaceCode(*code);
1061 JSFunction::EnsureLiterals(function);
1062
1063 // Check postconditions on success.
1064 DCHECK(!isolate->has_pending_exception());
1065 DCHECK(function->shared()->is_compiled());
1066 DCHECK(function->is_compiled());
1067 return true;
1068 }
1069
CompileBaseline(Handle<JSFunction> function)1070 bool Compiler::CompileBaseline(Handle<JSFunction> function) {
1071 Isolate* isolate = function->GetIsolate();
1072 DCHECK(AllowCompilation::IsAllowed(isolate));
1073
1074 // Start a compilation.
1075 Handle<Code> code;
1076 if (!GetBaselineCode(function).ToHandle(&code)) {
1077 // Baseline generation failed, get unoptimized code.
1078 DCHECK(function->shared()->is_compiled());
1079 code = handle(function->shared()->code());
1080 isolate->clear_pending_exception();
1081 }
1082
1083 // Install code on closure.
1084 function->ReplaceCode(*code);
1085 JSFunction::EnsureLiterals(function);
1086
1087 // Check postconditions on success.
1088 DCHECK(!isolate->has_pending_exception());
1089 DCHECK(function->shared()->is_compiled());
1090 DCHECK(function->is_compiled());
1091 return true;
1092 }
1093
CompileOptimized(Handle<JSFunction> function,ConcurrencyMode mode)1094 bool Compiler::CompileOptimized(Handle<JSFunction> function,
1095 ConcurrencyMode mode) {
1096 if (function->IsOptimized()) return true;
1097 Isolate* isolate = function->GetIsolate();
1098 DCHECK(AllowCompilation::IsAllowed(isolate));
1099
1100 // Start a compilation.
1101 Handle<Code> code;
1102 if (!GetOptimizedCode(function, mode).ToHandle(&code)) {
1103 // Optimization failed, get unoptimized code.
1104 DCHECK(!isolate->has_pending_exception());
1105 if (function->shared()->is_compiled()) {
1106 code = handle(function->shared()->code(), isolate);
1107 } else if (function->shared()->HasBytecodeArray()) {
1108 code = isolate->builtins()->InterpreterEntryTrampoline();
1109 function->shared()->ReplaceCode(*code);
1110 } else {
1111 Zone zone(isolate->allocator(), ZONE_NAME);
1112 ParseInfo parse_info(&zone, handle(function->shared()));
1113 CompilationInfo info(&parse_info, function);
1114 if (!GetUnoptimizedCode(&info).ToHandle(&code)) {
1115 return false;
1116 }
1117 }
1118 }
1119
1120 // Install code on closure.
1121 function->ReplaceCode(*code);
1122 JSFunction::EnsureLiterals(function);
1123
1124 // Check postconditions on success.
1125 DCHECK(!isolate->has_pending_exception());
1126 DCHECK(function->shared()->is_compiled());
1127 DCHECK(function->is_compiled());
1128 return true;
1129 }
1130
CompileDebugCode(Handle<SharedFunctionInfo> shared)1131 bool Compiler::CompileDebugCode(Handle<SharedFunctionInfo> shared) {
1132 Isolate* isolate = shared->GetIsolate();
1133 DCHECK(AllowCompilation::IsAllowed(isolate));
1134
1135 // Start a compilation.
1136 Zone zone(isolate->allocator(), ZONE_NAME);
1137 ParseInfo parse_info(&zone, shared);
1138 CompilationInfo info(&parse_info, Handle<JSFunction>::null());
1139 info.MarkAsDebug();
1140 if (GetUnoptimizedCode(&info).is_null()) {
1141 isolate->clear_pending_exception();
1142 return false;
1143 }
1144
1145 // Check postconditions on success.
1146 DCHECK(!isolate->has_pending_exception());
1147 DCHECK(shared->is_compiled());
1148 DCHECK(shared->HasDebugCode());
1149 return true;
1150 }
1151
CompileForLiveEdit(Handle<Script> script)1152 MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) {
1153 Isolate* isolate = script->GetIsolate();
1154 DCHECK(AllowCompilation::IsAllowed(isolate));
1155
1156 // In order to ensure that live edit function info collection finds the newly
1157 // generated shared function infos, clear the script's list temporarily
1158 // and restore it at the end of this method.
1159 Handle<Object> old_function_infos(script->shared_function_infos(), isolate);
1160 script->set_shared_function_infos(Smi::kZero);
1161
1162 // Start a compilation.
1163 Zone zone(isolate->allocator(), ZONE_NAME);
1164 ParseInfo parse_info(&zone, script);
1165 CompilationInfo info(&parse_info, Handle<JSFunction>::null());
1166 info.MarkAsDebug();
1167
1168 // TODO(635): support extensions.
1169 const bool compilation_succeeded = !CompileToplevel(&info).is_null();
1170 Handle<JSArray> infos;
1171 if (compilation_succeeded) {
1172 // Check postconditions on success.
1173 DCHECK(!isolate->has_pending_exception());
1174 infos = LiveEditFunctionTracker::Collect(parse_info.literal(), script,
1175 &zone, isolate);
1176 }
1177
1178 // Restore the original function info list in order to remain side-effect
1179 // free as much as possible, since some code expects the old shared function
1180 // infos to stick around.
1181 script->set_shared_function_infos(*old_function_infos);
1182
1183 return infos;
1184 }
1185
EnsureBytecode(CompilationInfo * info)1186 bool Compiler::EnsureBytecode(CompilationInfo* info) {
1187 if (!ShouldUseIgnition(info)) return false;
1188 if (!info->shared_info()->HasBytecodeArray()) {
1189 Handle<Code> original_code(info->shared_info()->code());
1190 if (GetUnoptimizedCode(info).is_null()) return false;
1191 if (info->shared_info()->HasAsmWasmData()) return false;
1192 DCHECK(info->shared_info()->is_compiled());
1193 if (original_code->kind() == Code::FUNCTION) {
1194 // Generating bytecode will install the {InterpreterEntryTrampoline} as
1195 // shared code on the function. To avoid an implicit tier down we restore
1196 // original baseline code in case it existed beforehand.
1197 info->shared_info()->ReplaceCode(*original_code);
1198 }
1199 }
1200 DCHECK(info->shared_info()->HasBytecodeArray());
1201 return true;
1202 }
1203
1204 // TODO(turbofan): In the future, unoptimized code with deopt support could
1205 // be generated lazily once deopt is triggered.
EnsureDeoptimizationSupport(CompilationInfo * info)1206 bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
1207 DCHECK_NOT_NULL(info->literal());
1208 DCHECK_NOT_NULL(info->scope());
1209 Handle<SharedFunctionInfo> shared = info->shared_info();
1210 if (!shared->has_deoptimization_support()) {
1211 Zone zone(info->isolate()->allocator(), ZONE_NAME);
1212 CompilationInfo unoptimized(info->parse_info(), info->closure());
1213 unoptimized.EnableDeoptimizationSupport();
1214
1215 // TODO(4280): For now we do not switch generators or async functions to
1216 // baseline code because there might be suspended activations stored in
1217 // generator objects on the heap. We could eventually go directly to
1218 // TurboFan in this case.
1219 if (IsResumableFunction(shared->kind())) return false;
1220
1221 // When we call PrepareForSerializing below, we will change the shared
1222 // ParseInfo. Make sure to reset it.
1223 bool old_will_serialize_value = info->parse_info()->will_serialize();
1224
1225 // If the current code has reloc info for serialization, also include
1226 // reloc info for serialization for the new code, so that deopt support
1227 // can be added without losing IC state.
1228 if (shared->code()->kind() == Code::FUNCTION &&
1229 shared->code()->has_reloc_info_for_serialization()) {
1230 unoptimized.PrepareForSerializing();
1231 }
1232 EnsureFeedbackMetadata(&unoptimized);
1233 if (!FullCodeGenerator::MakeCode(&unoptimized)) return false;
1234
1235 info->parse_info()->set_will_serialize(old_will_serialize_value);
1236
1237 // The scope info might not have been set if a lazily compiled
1238 // function is inlined before being called for the first time.
1239 if (shared->scope_info() == ScopeInfo::Empty(info->isolate())) {
1240 InstallSharedScopeInfo(info, shared);
1241 }
1242
1243 // Install compilation result on the shared function info
1244 shared->EnableDeoptimizationSupport(*unoptimized.code());
1245
1246 // The existing unoptimized code was replaced with the new one.
1247 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG,
1248 &unoptimized);
1249 }
1250 return true;
1251 }
1252
1253 // static
NextCompilationTier(JSFunction * function)1254 Compiler::CompilationTier Compiler::NextCompilationTier(JSFunction* function) {
1255 Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate());
1256 if (shared->IsInterpreted()) {
1257 if (UseTurboFan(shared)) {
1258 return OPTIMIZED;
1259 } else {
1260 return BASELINE;
1261 }
1262 } else {
1263 return OPTIMIZED;
1264 }
1265 }
1266
GetFunctionFromEval(Handle<String> source,Handle<SharedFunctionInfo> outer_info,Handle<Context> context,LanguageMode language_mode,ParseRestriction restriction,int eval_scope_position,int eval_position,int line_offset,int column_offset,Handle<Object> script_name,ScriptOriginOptions options)1267 MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
1268 Handle<String> source, Handle<SharedFunctionInfo> outer_info,
1269 Handle<Context> context, LanguageMode language_mode,
1270 ParseRestriction restriction, int eval_scope_position, int eval_position,
1271 int line_offset, int column_offset, Handle<Object> script_name,
1272 ScriptOriginOptions options) {
1273 Isolate* isolate = source->GetIsolate();
1274 int source_length = source->length();
1275 isolate->counters()->total_eval_size()->Increment(source_length);
1276 isolate->counters()->total_compile_size()->Increment(source_length);
1277
1278 CompilationCache* compilation_cache = isolate->compilation_cache();
1279 MaybeHandle<SharedFunctionInfo> maybe_shared_info =
1280 compilation_cache->LookupEval(source, outer_info, context, language_mode,
1281 eval_scope_position);
1282 Handle<SharedFunctionInfo> shared_info;
1283
1284 Handle<Script> script;
1285 if (!maybe_shared_info.ToHandle(&shared_info)) {
1286 script = isolate->factory()->NewScript(source);
1287 if (FLAG_trace_deopt) Script::InitLineEnds(script);
1288 if (!script_name.is_null()) {
1289 script->set_name(*script_name);
1290 script->set_line_offset(line_offset);
1291 script->set_column_offset(column_offset);
1292 }
1293 script->set_origin_options(options);
1294 script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
1295 Script::SetEvalOrigin(script, outer_info, eval_position);
1296
1297 Zone zone(isolate->allocator(), ZONE_NAME);
1298 ParseInfo parse_info(&zone, script);
1299 CompilationInfo info(&parse_info, Handle<JSFunction>::null());
1300 parse_info.set_eval();
1301 parse_info.set_language_mode(language_mode);
1302 parse_info.set_parse_restriction(restriction);
1303 if (!context->IsNativeContext()) {
1304 parse_info.set_outer_scope_info(handle(context->scope_info()));
1305 }
1306
1307 shared_info = CompileToplevel(&info);
1308
1309 if (shared_info.is_null()) {
1310 return MaybeHandle<JSFunction>();
1311 } else {
1312 // If caller is strict mode, the result must be in strict mode as well.
1313 DCHECK(is_sloppy(language_mode) ||
1314 is_strict(shared_info->language_mode()));
1315 compilation_cache->PutEval(source, outer_info, context, shared_info,
1316 eval_scope_position);
1317 }
1318 }
1319
1320 Handle<JSFunction> result =
1321 isolate->factory()->NewFunctionFromSharedFunctionInfo(
1322 shared_info, context, NOT_TENURED);
1323
1324 // OnAfterCompile has to be called after we create the JSFunction, which we
1325 // may require to recompile the eval for debugging, if we find a function
1326 // that contains break points in the eval script.
1327 isolate->debug()->OnAfterCompile(script);
1328
1329 return result;
1330 }
1331
1332 namespace {
1333
CodeGenerationFromStringsAllowed(Isolate * isolate,Handle<Context> context)1334 bool CodeGenerationFromStringsAllowed(Isolate* isolate,
1335 Handle<Context> context) {
1336 DCHECK(context->allow_code_gen_from_strings()->IsFalse(isolate));
1337 // Check with callback if set.
1338 AllowCodeGenerationFromStringsCallback callback =
1339 isolate->allow_code_gen_callback();
1340 if (callback == NULL) {
1341 // No callback set and code generation disallowed.
1342 return false;
1343 } else {
1344 // Callback set. Let it decide if code generation is allowed.
1345 VMState<EXTERNAL> state(isolate);
1346 return callback(v8::Utils::ToLocal(context));
1347 }
1348 }
1349
1350 } // namespace
1351
GetFunctionFromString(Handle<Context> context,Handle<String> source,ParseRestriction restriction)1352 MaybeHandle<JSFunction> Compiler::GetFunctionFromString(
1353 Handle<Context> context, Handle<String> source,
1354 ParseRestriction restriction) {
1355 Isolate* const isolate = context->GetIsolate();
1356 Handle<Context> native_context(context->native_context(), isolate);
1357
1358 // Check if native context allows code generation from
1359 // strings. Throw an exception if it doesn't.
1360 if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) &&
1361 !CodeGenerationFromStringsAllowed(isolate, native_context)) {
1362 Handle<Object> error_message =
1363 native_context->ErrorMessageForCodeGenerationFromStrings();
1364 THROW_NEW_ERROR(isolate, NewEvalError(MessageTemplate::kCodeGenFromStrings,
1365 error_message),
1366 JSFunction);
1367 }
1368
1369 // Compile source string in the native context.
1370 int eval_scope_position = 0;
1371 int eval_position = kNoSourcePosition;
1372 Handle<SharedFunctionInfo> outer_info(native_context->closure()->shared());
1373 return Compiler::GetFunctionFromEval(source, outer_info, native_context,
1374 SLOPPY, restriction, eval_scope_position,
1375 eval_position);
1376 }
1377
GetSharedFunctionInfoForScript(Handle<String> source,Handle<Object> script_name,int line_offset,int column_offset,ScriptOriginOptions resource_options,Handle<Object> source_map_url,Handle<Context> context,v8::Extension * extension,ScriptData ** cached_data,ScriptCompiler::CompileOptions compile_options,NativesFlag natives,bool is_module)1378 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
1379 Handle<String> source, Handle<Object> script_name, int line_offset,
1380 int column_offset, ScriptOriginOptions resource_options,
1381 Handle<Object> source_map_url, Handle<Context> context,
1382 v8::Extension* extension, ScriptData** cached_data,
1383 ScriptCompiler::CompileOptions compile_options, NativesFlag natives,
1384 bool is_module) {
1385 Isolate* isolate = source->GetIsolate();
1386 if (compile_options == ScriptCompiler::kNoCompileOptions) {
1387 cached_data = NULL;
1388 } else if (compile_options == ScriptCompiler::kProduceParserCache ||
1389 compile_options == ScriptCompiler::kProduceCodeCache) {
1390 DCHECK(cached_data && !*cached_data);
1391 DCHECK(extension == NULL);
1392 DCHECK(!isolate->debug()->is_loaded());
1393 } else {
1394 DCHECK(compile_options == ScriptCompiler::kConsumeParserCache ||
1395 compile_options == ScriptCompiler::kConsumeCodeCache);
1396 DCHECK(cached_data && *cached_data);
1397 DCHECK(extension == NULL);
1398 }
1399 int source_length = source->length();
1400 isolate->counters()->total_load_size()->Increment(source_length);
1401 isolate->counters()->total_compile_size()->Increment(source_length);
1402
1403 LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
1404 CompilationCache* compilation_cache = isolate->compilation_cache();
1405
1406 // Do a lookup in the compilation cache but not for extensions.
1407 MaybeHandle<SharedFunctionInfo> maybe_result;
1408 Handle<SharedFunctionInfo> result;
1409 if (extension == NULL) {
1410 // First check per-isolate compilation cache.
1411 maybe_result = compilation_cache->LookupScript(
1412 source, script_name, line_offset, column_offset, resource_options,
1413 context, language_mode);
1414 if (maybe_result.is_null() && FLAG_serialize_toplevel &&
1415 compile_options == ScriptCompiler::kConsumeCodeCache &&
1416 !isolate->debug()->is_loaded()) {
1417 // Then check cached code provided by embedder.
1418 HistogramTimerScope timer(isolate->counters()->compile_deserialize());
1419 RuntimeCallTimerScope runtimeTimer(isolate,
1420 &RuntimeCallStats::CompileDeserialize);
1421 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1422 "V8.CompileDeserialize");
1423 Handle<SharedFunctionInfo> result;
1424 if (CodeSerializer::Deserialize(isolate, *cached_data, source)
1425 .ToHandle(&result)) {
1426 // Promote to per-isolate compilation cache.
1427 compilation_cache->PutScript(source, context, language_mode, result);
1428 return result;
1429 }
1430 // Deserializer failed. Fall through to compile.
1431 }
1432 }
1433
1434 base::ElapsedTimer timer;
1435 if (FLAG_profile_deserialization && FLAG_serialize_toplevel &&
1436 compile_options == ScriptCompiler::kProduceCodeCache) {
1437 timer.Start();
1438 }
1439
1440 if (!maybe_result.ToHandle(&result) ||
1441 (FLAG_serialize_toplevel &&
1442 compile_options == ScriptCompiler::kProduceCodeCache)) {
1443 // No cache entry found, or embedder wants a code cache. Compile the script.
1444
1445 // Create a script object describing the script to be compiled.
1446 Handle<Script> script = isolate->factory()->NewScript(source);
1447 if (FLAG_trace_deopt) Script::InitLineEnds(script);
1448 if (natives == NATIVES_CODE) {
1449 script->set_type(Script::TYPE_NATIVE);
1450 script->set_hide_source(true);
1451 } else if (natives == EXTENSION_CODE) {
1452 script->set_type(Script::TYPE_EXTENSION);
1453 script->set_hide_source(true);
1454 }
1455 if (!script_name.is_null()) {
1456 script->set_name(*script_name);
1457 script->set_line_offset(line_offset);
1458 script->set_column_offset(column_offset);
1459 }
1460 script->set_origin_options(resource_options);
1461 if (!source_map_url.is_null()) {
1462 script->set_source_mapping_url(*source_map_url);
1463 }
1464
1465 // Compile the function and add it to the cache.
1466 Zone zone(isolate->allocator(), ZONE_NAME);
1467 ParseInfo parse_info(&zone, script);
1468 CompilationInfo info(&parse_info, Handle<JSFunction>::null());
1469 if (is_module) parse_info.set_module();
1470 if (compile_options != ScriptCompiler::kNoCompileOptions) {
1471 parse_info.set_cached_data(cached_data);
1472 }
1473 parse_info.set_compile_options(compile_options);
1474 parse_info.set_extension(extension);
1475 if (!context->IsNativeContext()) {
1476 parse_info.set_outer_scope_info(handle(context->scope_info()));
1477 }
1478 if (FLAG_serialize_toplevel &&
1479 compile_options == ScriptCompiler::kProduceCodeCache) {
1480 info.PrepareForSerializing();
1481 }
1482
1483 parse_info.set_language_mode(
1484 static_cast<LanguageMode>(parse_info.language_mode() | language_mode));
1485 result = CompileToplevel(&info);
1486 if (extension == NULL && !result.is_null()) {
1487 compilation_cache->PutScript(source, context, language_mode, result);
1488 if (FLAG_serialize_toplevel &&
1489 compile_options == ScriptCompiler::kProduceCodeCache) {
1490 HistogramTimerScope histogram_timer(
1491 isolate->counters()->compile_serialize());
1492 RuntimeCallTimerScope runtimeTimer(isolate,
1493 &RuntimeCallStats::CompileSerialize);
1494 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1495 "V8.CompileSerialize");
1496 *cached_data = CodeSerializer::Serialize(isolate, result, source);
1497 if (FLAG_profile_deserialization) {
1498 PrintF("[Compiling and serializing took %0.3f ms]\n",
1499 timer.Elapsed().InMillisecondsF());
1500 }
1501 }
1502 }
1503
1504 if (result.is_null()) {
1505 isolate->ReportPendingMessages();
1506 } else {
1507 isolate->debug()->OnAfterCompile(script);
1508 }
1509 } else if (result->ic_age() != isolate->heap()->global_ic_age()) {
1510 result->ResetForNewContext(isolate->heap()->global_ic_age());
1511 }
1512 return result;
1513 }
1514
GetSharedFunctionInfoForStreamedScript(Handle<Script> script,ParseInfo * parse_info,int source_length)1515 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForStreamedScript(
1516 Handle<Script> script, ParseInfo* parse_info, int source_length) {
1517 Isolate* isolate = script->GetIsolate();
1518 // TODO(titzer): increment the counters in caller.
1519 isolate->counters()->total_load_size()->Increment(source_length);
1520 isolate->counters()->total_compile_size()->Increment(source_length);
1521
1522 LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
1523 parse_info->set_language_mode(
1524 static_cast<LanguageMode>(parse_info->language_mode() | language_mode));
1525
1526 CompilationInfo compile_info(parse_info, Handle<JSFunction>::null());
1527
1528 // The source was parsed lazily, so compiling for debugging is not possible.
1529 DCHECK(!compile_info.is_debug());
1530
1531 Handle<SharedFunctionInfo> result = CompileToplevel(&compile_info);
1532 if (!result.is_null()) isolate->debug()->OnAfterCompile(script);
1533 return result;
1534 }
1535
1536
GetSharedFunctionInfo(FunctionLiteral * literal,Handle<Script> script,CompilationInfo * outer_info)1537 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
1538 FunctionLiteral* literal, Handle<Script> script,
1539 CompilationInfo* outer_info) {
1540 // Precondition: code has been parsed and scopes have been analyzed.
1541 Isolate* isolate = outer_info->isolate();
1542 MaybeHandle<SharedFunctionInfo> maybe_existing;
1543
1544 // Find any previously allocated shared function info for the given literal.
1545 if (outer_info->shared_info()->never_compiled()) {
1546 // On the first compile, there are no existing shared function info for
1547 // inner functions yet, so do not try to find them. All bets are off for
1548 // live edit though.
1549 SLOW_DCHECK(script->FindSharedFunctionInfo(literal).is_null() ||
1550 isolate->debug()->live_edit_enabled());
1551 } else {
1552 maybe_existing = script->FindSharedFunctionInfo(literal);
1553 }
1554
1555 // We found an existing shared function info. If it has any sort of code
1556 // attached, don't worry about compiling and simply return it. Otherwise,
1557 // continue to decide whether to eagerly compile.
1558 // Note that we also carry on if we are compiling eager to obtain code for
1559 // debugging, unless we already have code with debug break slots.
1560 Handle<SharedFunctionInfo> existing;
1561 if (maybe_existing.ToHandle(&existing)) {
1562 DCHECK(!existing->is_toplevel());
1563 if (existing->HasBaselineCode() || existing->HasBytecodeArray()) {
1564 if (!outer_info->is_debug() || existing->HasDebugCode()) {
1565 return existing;
1566 }
1567 }
1568 }
1569
1570 // Allocate a shared function info object.
1571 Handle<SharedFunctionInfo> result;
1572 if (!maybe_existing.ToHandle(&result)) {
1573 result = NewSharedFunctionInfoForLiteral(isolate, literal, script);
1574 result->set_is_toplevel(false);
1575
1576 // If the outer function has been compiled before, we cannot be sure that
1577 // shared function info for this function literal has been created for the
1578 // first time. It may have already been compiled previously.
1579 result->set_never_compiled(outer_info->shared_info()->never_compiled());
1580 }
1581
1582 Zone zone(isolate->allocator(), ZONE_NAME);
1583 ParseInfo parse_info(&zone, script);
1584 CompilationInfo info(&parse_info, Handle<JSFunction>::null());
1585 parse_info.set_literal(literal);
1586 parse_info.set_shared_info(result);
1587 parse_info.set_language_mode(literal->scope()->language_mode());
1588 parse_info.set_ast_value_factory(
1589 outer_info->parse_info()->ast_value_factory());
1590 parse_info.set_ast_value_factory_owned(false);
1591
1592 if (outer_info->will_serialize()) info.PrepareForSerializing();
1593 if (outer_info->is_debug()) info.MarkAsDebug();
1594
1595 // If this inner function is already compiled, we don't need to compile
1596 // again. When compiling for debug, we are not interested in having debug
1597 // break slots in inner functions, neither for setting break points nor
1598 // for revealing inner functions.
1599 // This is especially important for generators. We must not replace the
1600 // code for generators, as there may be suspended generator objects.
1601 if (!result->is_compiled()) {
1602 if (!literal->ShouldEagerCompile()) {
1603 info.SetCode(isolate->builtins()->CompileLazy());
1604 Scope* outer_scope = literal->scope()->GetOuterScopeWithContext();
1605 if (outer_scope) {
1606 result->set_outer_scope_info(*outer_scope->scope_info());
1607 }
1608 } else {
1609 // Generate code
1610 TimerEventScope<TimerEventCompileCode> timer(isolate);
1611 RuntimeCallTimerScope runtimeTimer(isolate,
1612 &RuntimeCallStats::CompileCode);
1613 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode");
1614 if (Renumber(info.parse_info()) && GenerateUnoptimizedCode(&info)) {
1615 // Code generation will ensure that the feedback vector is present and
1616 // appropriately sized.
1617 DCHECK(!info.code().is_null());
1618 if (literal->should_be_used_once_hint()) {
1619 info.code()->MarkToBeExecutedOnce(isolate);
1620 }
1621 } else {
1622 return Handle<SharedFunctionInfo>::null();
1623 }
1624 }
1625 }
1626
1627 if (maybe_existing.is_null()) {
1628 RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, &info);
1629 }
1630
1631 return result;
1632 }
1633
GetSharedFunctionInfoForNative(v8::Extension * extension,Handle<String> name)1634 Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForNative(
1635 v8::Extension* extension, Handle<String> name) {
1636 Isolate* isolate = name->GetIsolate();
1637 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
1638
1639 // Compute the function template for the native function.
1640 v8::Local<v8::FunctionTemplate> fun_template =
1641 extension->GetNativeFunctionTemplate(v8_isolate,
1642 v8::Utils::ToLocal(name));
1643 DCHECK(!fun_template.IsEmpty());
1644
1645 // Instantiate the function and create a shared function info from it.
1646 Handle<JSFunction> fun = Handle<JSFunction>::cast(Utils::OpenHandle(
1647 *fun_template->GetFunction(v8_isolate->GetCurrentContext())
1648 .ToLocalChecked()));
1649 Handle<Code> code = Handle<Code>(fun->shared()->code());
1650 Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub());
1651 Handle<SharedFunctionInfo> shared = isolate->factory()->NewSharedFunctionInfo(
1652 name, fun->shared()->num_literals(), FunctionKind::kNormalFunction, code,
1653 Handle<ScopeInfo>(fun->shared()->scope_info()));
1654 shared->set_outer_scope_info(fun->shared()->outer_scope_info());
1655 shared->SetConstructStub(*construct_stub);
1656 shared->set_feedback_metadata(fun->shared()->feedback_metadata());
1657
1658 // Copy the function data to the shared function info.
1659 shared->set_function_data(fun->shared()->function_data());
1660 int parameters = fun->shared()->internal_formal_parameter_count();
1661 shared->set_internal_formal_parameter_count(parameters);
1662
1663 return shared;
1664 }
1665
GetOptimizedCodeForOSR(Handle<JSFunction> function,BailoutId osr_ast_id,JavaScriptFrame * osr_frame)1666 MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function,
1667 BailoutId osr_ast_id,
1668 JavaScriptFrame* osr_frame) {
1669 DCHECK(!osr_ast_id.IsNone());
1670 DCHECK_NOT_NULL(osr_frame);
1671 return GetOptimizedCode(function, NOT_CONCURRENT, osr_ast_id, osr_frame);
1672 }
1673
PrepareUnoptimizedCompilationJob(CompilationInfo * info)1674 CompilationJob* Compiler::PrepareUnoptimizedCompilationJob(
1675 CompilationInfo* info) {
1676 VMState<COMPILER> state(info->isolate());
1677 std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info));
1678 if (job->PrepareJob() != CompilationJob::SUCCEEDED) {
1679 return nullptr;
1680 }
1681 return job.release();
1682 }
1683
FinalizeCompilationJob(CompilationJob * raw_job)1684 bool Compiler::FinalizeCompilationJob(CompilationJob* raw_job) {
1685 // Take ownership of compilation job. Deleting job also tears down the zone.
1686 std::unique_ptr<CompilationJob> job(raw_job);
1687
1688 VMState<COMPILER> state(job->info()->isolate());
1689 if (job->info()->IsOptimizing()) {
1690 return FinalizeOptimizedCompilationJob(job.get()) ==
1691 CompilationJob::SUCCEEDED;
1692 } else {
1693 if (FinalizeUnoptimizedCompilationJob(job.get()) ==
1694 CompilationJob::SUCCEEDED) {
1695 RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG,
1696 job->info());
1697 return true;
1698 }
1699 return false;
1700 }
1701 }
1702
PostInstantiation(Handle<JSFunction> function,PretenureFlag pretenure)1703 void Compiler::PostInstantiation(Handle<JSFunction> function,
1704 PretenureFlag pretenure) {
1705 Handle<SharedFunctionInfo> shared(function->shared());
1706
1707 if (FLAG_always_opt && shared->allows_lazy_compilation()) {
1708 function->MarkForOptimization();
1709 }
1710
1711 CodeAndLiterals cached = shared->SearchOptimizedCodeMap(
1712 function->context()->native_context(), BailoutId::None());
1713 if (cached.code != nullptr) {
1714 // Caching of optimized code enabled and optimized code found.
1715 DCHECK(!cached.code->marked_for_deoptimization());
1716 DCHECK(function->shared()->is_compiled());
1717 function->ReplaceCode(cached.code);
1718 }
1719
1720 if (cached.literals != nullptr) {
1721 DCHECK(shared->is_compiled());
1722 function->set_literals(cached.literals);
1723 } else if (shared->is_compiled()) {
1724 // TODO(mvstanton): pass pretenure flag to EnsureLiterals.
1725 JSFunction::EnsureLiterals(function);
1726 }
1727 }
1728
1729 } // namespace internal
1730 } // namespace v8
1731