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