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#ifndef V8_COMPILER_H_
6#define V8_COMPILER_H_
7
8#include <forward_list>
9#include <memory>
10
11#include "src/allocation.h"
12#include "src/bailout-reason.h"
13#include "src/base/platform/elapsed-timer.h"
14#include "src/code-events.h"
15#include "src/contexts.h"
16#include "src/isolate.h"
17#include "src/zone/zone.h"
18
19namespace v8 {
20namespace internal {
21
22// Forward declarations.
23class AstRawString;
24class BackgroundCompileTask;
25class IsCompiledScope;
26class JavaScriptFrame;
27class OptimizedCompilationInfo;
28class OptimizedCompilationJob;
29class ParseInfo;
30class Parser;
31class ScriptData;
32struct ScriptStreamingData;
33class TimedHistogram;
34class UnoptimizedCompilationInfo;
35class UnoptimizedCompilationJob;
36class WorkerThreadRuntimeCallStats;
37
38typedef std::forward_list<std::unique_ptr<UnoptimizedCompilationJob>>
39 UnoptimizedCompilationJobList;
40
41// The V8 compiler API.
42//
43// This is the central hub for dispatching to the various compilers within V8.
44// Logic for which compiler to choose and how to wire compilation results into
45// the object heap should be kept inside this class.
46//
47// General strategy: Scripts are translated into anonymous functions w/o
48// parameters which then can be executed. If the source code contains other
49// functions, they might be compiled and allocated as part of the compilation
50// of the source code or deferred for lazy compilation at a later point.
51class V8_EXPORT_PRIVATE Compiler : public AllStatic {
52 public:
53 enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION };
54
55 // ===========================================================================
56 // The following family of methods ensures a given function is compiled. The
57 // general contract is that failures will be reported by returning {false},
58 // whereas successful compilation ensures the {is_compiled} predicate on the
59 // given function holds (except for live-edit, which compiles the world).
60
61 static bool Compile(Handle<SharedFunctionInfo> shared,
62 ClearExceptionFlag flag,
63 IsCompiledScope* is_compiled_scope);
64 static bool Compile(Handle<JSFunction> function, ClearExceptionFlag flag,
65 IsCompiledScope* is_compiled_scope);
66 static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode);
67
68 // Collect source positions for a function that has already been compiled to
69 // bytecode, but for which source positions were not collected (e.g. because
70 // they were not immediately needed).
71 static bool CollectSourcePositions(Isolate* isolate,
72 Handle<SharedFunctionInfo> shared);
73
74 V8_WARN_UNUSED_RESULT static MaybeHandle<SharedFunctionInfo>
75 CompileForLiveEdit(ParseInfo* parse_info, Isolate* isolate);
76
77 // Finalize and install code from previously run background compile task.
78 static bool FinalizeBackgroundCompileTask(
79 BackgroundCompileTask* task, Handle<SharedFunctionInfo> shared_info,
80 Isolate* isolate, ClearExceptionFlag flag);
81
82 // Finalize and install optimized code from previously run job.
83 static bool FinalizeOptimizedCompilationJob(OptimizedCompilationJob* job,
84 Isolate* isolate);
85
86 // Give the compiler a chance to perform low-latency initialization tasks of
87 // the given {function} on its instantiation. Note that only the runtime will
88 // offer this chance, optimized closure instantiation will not call this.
89 static void PostInstantiation(Handle<JSFunction> function, AllocationType);
90
91 // Parser::Parse, then Compiler::Analyze.
92 static bool ParseAndAnalyze(ParseInfo* parse_info,
93 Handle<SharedFunctionInfo> shared_info,
94 Isolate* isolate);
95 // Rewrite and analyze scopes.
96 static bool Analyze(ParseInfo* parse_info);
97
98 // ===========================================================================
99 // The following family of methods instantiates new functions for scripts or
100 // function literals. The decision whether those functions will be compiled,
101 // is left to the discretion of the compiler.
102 //
103 // Please note this interface returns shared function infos. This means you
104 // need to call Factory::NewFunctionFromSharedFunctionInfo before you have a
105 // real function with a context.
106
107 // Create a (bound) function for a String source within a context for eval.
108 V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval(
109 Handle<String> source, Handle<SharedFunctionInfo> outer_info,
110 Handle<Context> context, LanguageMode language_mode,
111 ParseRestriction restriction, int parameters_end_pos,
112 int eval_scope_position, int eval_position);
113
114 struct ScriptDetails {
115 ScriptDetails() : line_offset(0), column_offset(0) {}
116 explicit ScriptDetails(Handle<Object> script_name)
117 : line_offset(0), column_offset(0), name_obj(script_name) {}
118
119 int line_offset;
120 int column_offset;
121 i::MaybeHandle<i::Object> name_obj;
122 i::MaybeHandle<i::Object> source_map_url;
123 i::MaybeHandle<i::FixedArray> host_defined_options;
124 };
125
126 // Create a function that results from wrapping |source| in a function,
127 // with |arguments| being a list of parameters for that function.
128 V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetWrappedFunction(
129 Handle<String> source, Handle<FixedArray> arguments,
130 Handle<Context> context, const ScriptDetails& script_details,
131 ScriptOriginOptions origin_options, ScriptData* cached_data,
132 v8::ScriptCompiler::CompileOptions compile_options,
133 v8::ScriptCompiler::NoCacheReason no_cache_reason);
134
135 // Returns true if the embedder permits compiling the given source string in
136 // the given context.
137 static bool CodeGenerationFromStringsAllowed(Isolate* isolate,
138 Handle<Context> context,
139 Handle<String> source);
140
141 // Create a (bound) function for a String source within a context for eval.
142 V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetFunctionFromString(
143 Handle<Context> context, Handle<String> source,
144 ParseRestriction restriction, int parameters_end_pos);
145
146 // Create a shared function info object for a String source.
147 static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScript(
148 Isolate* isolate, Handle<String> source,
149 const ScriptDetails& script_details, ScriptOriginOptions origin_options,
150 v8::Extension* extension, ScriptData* cached_data,
151 ScriptCompiler::CompileOptions compile_options,
152 ScriptCompiler::NoCacheReason no_cache_reason,
153 NativesFlag is_natives_code);
154
155 // Create a shared function info object for a Script source that has already
156 // been parsed and possibly compiled on a background thread while being loaded
157 // from a streamed source. On return, the data held by |streaming_data| will
158 // have been released, however the object itself isn't freed and is still
159 // owned by the caller.
160 static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForStreamedScript(
161 Isolate* isolate, Handle<String> source,
162 const ScriptDetails& script_details, ScriptOriginOptions origin_options,
163 ScriptStreamingData* streaming_data);
164
165 // Create a shared function info object for the given function literal
166 // node (the code may be lazily compiled).
167 static Handle<SharedFunctionInfo> GetSharedFunctionInfo(FunctionLiteral* node,
168 Handle<Script> script,
169 Isolate* isolate);
170
171 // ===========================================================================
172 // The following family of methods provides support for OSR. Code generated
173 // for entry via OSR might not be suitable for normal entry, hence will be
174 // returned directly to the caller.
175 //
176 // Please note this interface is the only part dealing with {Code} objects
177 // directly. Other methods are agnostic to {Code} and can use an interpreter
178 // instead of generating JIT code for a function at all.
179
180 // Generate and return optimized code for OSR, or empty handle on failure.
181 V8_WARN_UNUSED_RESULT static MaybeHandle<Code> GetOptimizedCodeForOSR(
182 Handle<JSFunction> function, BailoutId osr_offset,
183 JavaScriptFrame* osr_frame);
184};
185
186// A base class for compilation jobs intended to run concurrent to the main
187// thread. The current state of the job can be checked using {state()}.
188class V8_EXPORT_PRIVATE CompilationJob {
189 public:
190 enum Status { SUCCEEDED, FAILED };
191 enum class State {
192 kReadyToPrepare,
193 kReadyToExecute,
194 kReadyToFinalize,
195 kSucceeded,
196 kFailed,
197 };
198
199 CompilationJob(uintptr_t stack_limit, State initial_state)
200 : state_(initial_state), stack_limit_(stack_limit) {
201 timer_.Start();
202 }
203 virtual ~CompilationJob() = default;
204
205 void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
206 uintptr_t stack_limit() const { return stack_limit_; }
207
208 State state() const { return state_; }
209
210 protected:
211 V8_WARN_UNUSED_RESULT base::TimeDelta ElapsedTime() const {
212 return timer_.Elapsed();
213 }
214
215 V8_WARN_UNUSED_RESULT Status UpdateState(Status status, State next_state) {
216 if (status == SUCCEEDED) {
217 state_ = next_state;
218 } else {
219 state_ = State::kFailed;
220 }
221 return status;
222 }
223
224 private:
225 State state_;
226 uintptr_t stack_limit_;
227 base::ElapsedTimer timer_;
228};
229
230// A base class for unoptimized compilation jobs.
231//
232// The job is split into two phases which are called in sequence on
233// different threads and with different limitations:
234// 1) ExecuteJob: Runs concurrently. No heap allocation or handle derefs.
235// 2) FinalizeJob: Runs on main thread. No dependency changes.
236//
237// Either of phases can either fail or succeed.
238class UnoptimizedCompilationJob : public CompilationJob {
239 public:
240 UnoptimizedCompilationJob(intptr_t stack_limit, ParseInfo* parse_info,
241 UnoptimizedCompilationInfo* compilation_info)
242 : CompilationJob(stack_limit, State::kReadyToExecute),
243 parse_info_(parse_info),
244 compilation_info_(compilation_info) {}
245
246 // Executes the compile job. Can be called on a background thread.
247 V8_WARN_UNUSED_RESULT Status ExecuteJob();
248
249 // Finalizes the compile job. Must be called on the main thread.
250 V8_WARN_UNUSED_RESULT Status
251 FinalizeJob(Handle<SharedFunctionInfo> shared_info, Isolate* isolate);
252
253 void RecordCompilationStats(Isolate* isolate) const;
254 void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
255 Handle<SharedFunctionInfo> shared,
256 Isolate* isolate) const;
257
258 ParseInfo* parse_info() const { return parse_info_; }
259 UnoptimizedCompilationInfo* compilation_info() const {
260 return compilation_info_;
261 }
262
263 protected:
264 // Overridden by the actual implementation.
265 virtual Status ExecuteJobImpl() = 0;
266 virtual Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info,
267 Isolate* isolate) = 0;
268
269 private:
270 ParseInfo* parse_info_;
271 UnoptimizedCompilationInfo* compilation_info_;
272 base::TimeDelta time_taken_to_execute_;
273 base::TimeDelta time_taken_to_finalize_;
274};
275
276// A base class for optimized compilation jobs.
277//
278// The job is split into three phases which are called in sequence on
279// different threads and with different limitations:
280// 1) PrepareJob: Runs on main thread. No major limitations.
281// 2) ExecuteJob: Runs concurrently. No heap allocation or handle derefs.
282// 3) FinalizeJob: Runs on main thread. No dependency changes.
283//
284// Each of the three phases can either fail or succeed.
285class OptimizedCompilationJob : public CompilationJob {
286 public:
287 OptimizedCompilationJob(uintptr_t stack_limit,
288 OptimizedCompilationInfo* compilation_info,
289 const char* compiler_name,
290 State initial_state = State::kReadyToPrepare)
291 : CompilationJob(stack_limit, initial_state),
292 compilation_info_(compilation_info),
293 compiler_name_(compiler_name) {}
294
295 // Prepare the compile job. Must be called on the main thread.
296 V8_WARN_UNUSED_RESULT Status PrepareJob(Isolate* isolate);
297
298 // Executes the compile job. Can be called on a background thread if
299 // can_execute_on_background_thread() returns true.
300 V8_WARN_UNUSED_RESULT Status ExecuteJob();
301
302 // Finalizes the compile job. Must be called on the main thread.
303 V8_WARN_UNUSED_RESULT Status FinalizeJob(Isolate* isolate);
304
305 // Report a transient failure, try again next time. Should only be called on
306 // optimization compilation jobs.
307 Status RetryOptimization(BailoutReason reason);
308
309 // Report a persistent failure, disable future optimization on the function.
310 // Should only be called on optimization compilation jobs.
311 Status AbortOptimization(BailoutReason reason);
312
313 enum CompilationMode { kConcurrent, kSynchronous };
314 void RecordCompilationStats(CompilationMode mode, Isolate* isolate) const;
315 void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
316 Isolate* isolate) const;
317
318 OptimizedCompilationInfo* compilation_info() const {
319 return compilation_info_;
320 }
321
322 protected:
323 // Overridden by the actual implementation.
324 virtual Status PrepareJobImpl(Isolate* isolate) = 0;
325 virtual Status ExecuteJobImpl() = 0;
326 virtual Status FinalizeJobImpl(Isolate* isolate) = 0;
327
328 private:
329 OptimizedCompilationInfo* compilation_info_;
330 base::TimeDelta time_taken_to_prepare_;
331 base::TimeDelta time_taken_to_execute_;
332 base::TimeDelta time_taken_to_finalize_;
333 const char* compiler_name_;
334};
335
336class V8_EXPORT_PRIVATE BackgroundCompileTask {
337 public:
338 // Creates a new task that when run will parse and compile the streamed
339 // script associated with |data| and can be finalized with
340 // Compiler::GetSharedFunctionInfoForStreamedScript.
341 // Note: does not take ownership of |data|.
342 BackgroundCompileTask(ScriptStreamingData* data, Isolate* isolate);
343 ~BackgroundCompileTask();
344
345 // Creates a new task that when run will parse and compile the
346 // |function_literal| and can be finalized with
347 // Compiler::FinalizeBackgroundCompileTask.
348 BackgroundCompileTask(
349 AccountingAllocator* allocator, const ParseInfo* outer_parse_info,
350 const AstRawString* function_name,
351 const FunctionLiteral* function_literal,
352 WorkerThreadRuntimeCallStats* worker_thread_runtime_stats,
353 TimedHistogram* timer, int max_stack_size);
354
355 void Run();
356
357 ParseInfo* info() { return info_.get(); }
358 Parser* parser() { return parser_.get(); }
359 UnoptimizedCompilationJob* outer_function_job() {
360 return outer_function_job_.get();
361 }
362 UnoptimizedCompilationJobList* inner_function_jobs() {
363 return &inner_function_jobs_;
364 }
365
366 private:
367 // Data needed for parsing, and data needed to to be passed between thread
368 // between parsing and compilation. These need to be initialized before the
369 // compilation starts.
370 std::unique_ptr<ParseInfo> info_;
371 std::unique_ptr<Parser> parser_;
372
373 // Data needed for finalizing compilation after background compilation.
374 std::unique_ptr<UnoptimizedCompilationJob> outer_function_job_;
375 UnoptimizedCompilationJobList inner_function_jobs_;
376
377 int stack_size_;
378 WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats_;
379 AccountingAllocator* allocator_;
380 TimedHistogram* timer_;
381
382 DISALLOW_COPY_AND_ASSIGN(BackgroundCompileTask);
383};
384
385// Contains all data which needs to be transmitted between threads for
386// background parsing and compiling and finalizing it on the main thread.
387struct ScriptStreamingData {
388 ScriptStreamingData(
389 std::unique_ptr<ScriptCompiler::ExternalSourceStream> source_stream,
390 ScriptCompiler::StreamedSource::Encoding encoding);
391 ~ScriptStreamingData();
392
393 void Release();
394
395 // Internal implementation of v8::ScriptCompiler::StreamedSource.
396 std::unique_ptr<ScriptCompiler::ExternalSourceStream> source_stream;
397 ScriptCompiler::StreamedSource::Encoding encoding;
398
399 // Task that performs background parsing and compilation.
400 std::unique_ptr<BackgroundCompileTask> task;
401
402 DISALLOW_COPY_AND_ASSIGN(ScriptStreamingData);
403};
404
405} // namespace internal
406} // namespace v8
407
408#endif // V8_COMPILER_H_
409