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