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