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 <memory>
9 
10 #include "src/allocation.h"
11 #include "src/bailout-reason.h"
12 #include "src/contexts.h"
13 #include "src/isolate.h"
14 #include "src/zone/zone.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 // Forward declarations.
20 class CompilationInfo;
21 class CompilationJob;
22 class JavaScriptFrame;
23 class ParseInfo;
24 class ScriptData;
25 template <typename T>
26 class ThreadedList;
27 template <typename T>
28 class ThreadedListZoneEntry;
29 
30 // The V8 compiler API.
31 //
32 // This is the central hub for dispatching to the various compilers within V8.
33 // Logic for which compiler to choose and how to wire compilation results into
34 // the object heap should be kept inside this class.
35 //
36 // General strategy: Scripts are translated into anonymous functions w/o
37 // parameters which then can be executed. If the source code contains other
38 // functions, they might be compiled and allocated as part of the compilation
39 // of the source code or deferred for lazy compilation at a later point.
40 class V8_EXPORT_PRIVATE Compiler : public AllStatic {
41  public:
42   enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION };
43   enum ConcurrencyMode { NOT_CONCURRENT, CONCURRENT };
44   enum CompilationTier { INTERPRETED, BASELINE, OPTIMIZED };
45 
46   // ===========================================================================
47   // The following family of methods ensures a given function is compiled. The
48   // general contract is that failures will be reported by returning {false},
49   // whereas successful compilation ensures the {is_compiled} predicate on the
50   // given function holds (except for live-edit, which compiles the world).
51 
52   static bool Compile(Handle<JSFunction> function, ClearExceptionFlag flag);
53   static bool CompileBaseline(Handle<JSFunction> function);
54   static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode);
55   static bool CompileDebugCode(Handle<SharedFunctionInfo> shared);
56   static MaybeHandle<JSArray> CompileForLiveEdit(Handle<Script> script);
57 
58   // Prepare a compilation job for unoptimized code. Requires ParseAndAnalyse.
59   static CompilationJob* PrepareUnoptimizedCompilationJob(
60       CompilationInfo* info);
61 
62   // Generate and install code from previously queued compilation job.
63   static bool FinalizeCompilationJob(CompilationJob* job);
64 
65   // Give the compiler a chance to perform low-latency initialization tasks of
66   // the given {function} on its instantiation. Note that only the runtime will
67   // offer this chance, optimized closure instantiation will not call this.
68   static void PostInstantiation(Handle<JSFunction> function, PretenureFlag);
69 
70   typedef ThreadedList<ThreadedListZoneEntry<FunctionLiteral*>>
71       EagerInnerFunctionLiterals;
72 
73   // Parser::Parse, then Compiler::Analyze.
74   static bool ParseAndAnalyze(ParseInfo* info);
75   // Rewrite, analyze scopes, and renumber. If |eager_literals| is non-null, it
76   // is appended with inner function literals which should be eagerly compiled.
77   static bool Analyze(ParseInfo* info,
78                       EagerInnerFunctionLiterals* eager_literals = nullptr);
79   // Adds deoptimization support, requires ParseAndAnalyze.
80   static bool EnsureDeoptimizationSupport(CompilationInfo* info);
81   // Ensures that bytecode is generated, calls ParseAndAnalyze internally.
82   static bool EnsureBytecode(CompilationInfo* info);
83 
84   // The next compilation tier which the function should  be compiled to for
85   // optimization. This is used as a hint by the runtime profiler.
86   static CompilationTier NextCompilationTier(JSFunction* function);
87 
88   // ===========================================================================
89   // The following family of methods instantiates new functions for scripts or
90   // function literals. The decision whether those functions will be compiled,
91   // is left to the discretion of the compiler.
92   //
93   // Please note this interface returns shared function infos.  This means you
94   // need to call Factory::NewFunctionFromSharedFunctionInfo before you have a
95   // real function with a context.
96 
97   // Create a (bound) function for a String source within a context for eval.
98   MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval(
99       Handle<String> source, Handle<SharedFunctionInfo> outer_info,
100       Handle<Context> context, LanguageMode language_mode,
101       ParseRestriction restriction, int parameters_end_pos,
102       int eval_scope_position, int eval_position, int line_offset = 0,
103       int column_offset = 0, Handle<Object> script_name = Handle<Object>(),
104       ScriptOriginOptions options = ScriptOriginOptions());
105 
106   // Create a (bound) function for a String source within a context for eval.
107   MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromString(
108       Handle<Context> context, Handle<String> source,
109       ParseRestriction restriction, int parameters_end_pos);
110 
111   // Create a shared function info object for a String source within a context.
112   static Handle<SharedFunctionInfo> GetSharedFunctionInfoForScript(
113       Handle<String> source, Handle<Object> script_name, int line_offset,
114       int column_offset, ScriptOriginOptions resource_options,
115       Handle<Object> source_map_url, Handle<Context> context,
116       v8::Extension* extension, ScriptData** cached_data,
117       ScriptCompiler::CompileOptions compile_options,
118       NativesFlag is_natives_code);
119 
120   // Create a shared function info object for a Script that has already been
121   // parsed while the script was being loaded from a streamed source.
122   static Handle<SharedFunctionInfo> GetSharedFunctionInfoForStreamedScript(
123       Handle<Script> script, ParseInfo* info, int source_length);
124 
125   // Create a shared function info object (the code may be lazily compiled).
126   static Handle<SharedFunctionInfo> GetSharedFunctionInfo(
127       FunctionLiteral* node, Handle<Script> script, CompilationInfo* outer);
128 
129   // Create a shared function info object for a native function literal.
130   static Handle<SharedFunctionInfo> GetSharedFunctionInfoForNative(
131       v8::Extension* extension, Handle<String> name);
132 
133   // ===========================================================================
134   // The following family of methods provides support for OSR. Code generated
135   // for entry via OSR might not be suitable for normal entry, hence will be
136   // returned directly to the caller.
137   //
138   // Please note this interface is the only part dealing with {Code} objects
139   // directly. Other methods are agnostic to {Code} and can use an interpreter
140   // instead of generating JIT code for a function at all.
141 
142   // Generate and return optimized code for OSR, or empty handle on failure.
143   MUST_USE_RESULT static MaybeHandle<Code> GetOptimizedCodeForOSR(
144       Handle<JSFunction> function, BailoutId osr_ast_id,
145       JavaScriptFrame* osr_frame);
146 };
147 
148 // A base class for compilation jobs intended to run concurrent to the main
149 // thread. The job is split into three phases which are called in sequence on
150 // different threads and with different limitations:
151 //  1) PrepareJob:   Runs on main thread. No major limitations.
152 //  2) ExecuteJob:   Runs concurrently. No heap allocation or handle derefs.
153 //  3) FinalizeJob:  Runs on main thread. No dependency changes.
154 //
155 // Each of the three phases can either fail or succeed. The current state of
156 // the job can be checked using {state()}.
157 class V8_EXPORT_PRIVATE CompilationJob {
158  public:
159   enum Status { SUCCEEDED, FAILED };
160   enum class State {
161     kReadyToPrepare,
162     kReadyToExecute,
163     kReadyToFinalize,
164     kSucceeded,
165     kFailed,
166   };
167 
168   CompilationJob(Isolate* isolate, CompilationInfo* info,
169                  const char* compiler_name,
170                  State initial_state = State::kReadyToPrepare);
~CompilationJob()171   virtual ~CompilationJob() {}
172 
173   // Prepare the compile job. Must be called on the main thread.
174   MUST_USE_RESULT Status PrepareJob();
175 
176   // Executes the compile job. Can be called on a background thread if
177   // can_execute_on_background_thread() returns true.
178   MUST_USE_RESULT Status ExecuteJob();
179 
180   // Finalizes the compile job. Must be called on the main thread.
181   MUST_USE_RESULT Status FinalizeJob();
182 
183   // Report a transient failure, try again next time. Should only be called on
184   // optimization compilation jobs.
185   Status RetryOptimization(BailoutReason reason);
186 
187   // Report a persistent failure, disable future optimization on the function.
188   // Should only be called on optimization compilation jobs.
189   Status AbortOptimization(BailoutReason reason);
190 
191   void RecordOptimizedCompilationStats() const;
192   void RecordUnoptimizedCompilationStats() const;
193 
can_execute_on_background_thread()194   virtual bool can_execute_on_background_thread() const { return true; }
195 
set_stack_limit(uintptr_t stack_limit)196   void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
stack_limit()197   uintptr_t stack_limit() const { return stack_limit_; }
198 
executed_on_background_thread()199   bool executed_on_background_thread() const {
200     DCHECK_IMPLIES(!can_execute_on_background_thread(),
201                    !executed_on_background_thread_);
202     return executed_on_background_thread_;
203   }
state()204   State state() const { return state_; }
info()205   CompilationInfo* info() const { return info_; }
206   Isolate* isolate() const;
207 
208  protected:
209   // Overridden by the actual implementation.
210   virtual Status PrepareJobImpl() = 0;
211   virtual Status ExecuteJobImpl() = 0;
212   virtual Status FinalizeJobImpl() = 0;
213 
214   // Registers weak object to optimized code dependencies.
215   // TODO(turbofan): Move this to pipeline.cc once Crankshaft dies.
216   void RegisterWeakObjectsInOptimizedCode(Handle<Code> code);
217 
218  private:
219   CompilationInfo* info_;
220   ThreadId isolate_thread_id_;
221   base::TimeDelta time_taken_to_prepare_;
222   base::TimeDelta time_taken_to_execute_;
223   base::TimeDelta time_taken_to_finalize_;
224   const char* compiler_name_;
225   State state_;
226   uintptr_t stack_limit_;
227   bool executed_on_background_thread_;
228 
UpdateState(Status status,State next_state)229   MUST_USE_RESULT Status UpdateState(Status status, State next_state) {
230     if (status == SUCCEEDED) {
231       state_ = next_state;
232     } else {
233       state_ = State::kFailed;
234     }
235     return status;
236   }
237 };
238 
239 }  // namespace internal
240 }  // namespace v8
241 
242 #endif  // V8_COMPILER_H_
243