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