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