Home | History | Annotate | Download | only in src
      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 {
    109     ScriptDetails() : line_offset(0), column_offset(0) {}
    110     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 
    193   CompilationJob(uintptr_t stack_limit, State initial_state)
    194       : state_(initial_state), stack_limit_(stack_limit) {}
    195   virtual ~CompilationJob() {}
    196 
    197   void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
    198   uintptr_t stack_limit() const { return stack_limit_; }
    199 
    200   State state() const { return state_; }
    201 
    202  protected:
    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:
    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 
    245   ParseInfo* parse_info() const { return parse_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)
    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 
    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