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 : #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 :
19 : namespace v8 {
20 : namespace internal {
21 :
22 : // Forward declarations.
23 : class AstRawString;
24 : class BackgroundCompileTask;
25 : class IsCompiledScope;
26 : class JavaScriptFrame;
27 : class OptimizedCompilationInfo;
28 : class OptimizedCompilationJob;
29 : class ParseInfo;
30 : class Parser;
31 : class ScriptData;
32 : struct ScriptStreamingData;
33 : class TimedHistogram;
34 : class UnoptimizedCompilationInfo;
35 : class UnoptimizedCompilationJob;
36 : class WorkerThreadRuntimeCallStats;
37 :
38 : typedef 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.
51 : class 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 275758 : ScriptDetails() : line_offset(0), column_offset(0) {}
116 : explicit ScriptDetails(Handle<Object> script_name)
117 12792 : : 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()}.
188 : class 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 2599890 : : state_(initial_state), stack_limit_(stack_limit) {
201 : timer_.Start();
202 : }
203 2599921 : 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 5596526 : if (status == SUCCEEDED) {
217 5595158 : state_ = next_state;
218 : } else {
219 1463 : 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.
238 4240182 : class 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 2120074 : 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.
285 959660 : class 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 959658 : 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 :
336 26950 : class 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 203 : 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.
387 26790 : struct 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_
|