| // Copyright 2012 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_COMPILER_H_ |
| #define V8_COMPILER_H_ |
| |
| #include <forward_list> |
| #include <memory> |
| |
| #include "src/allocation.h" |
| #include "src/bailout-reason.h" |
| #include "src/code-events.h" |
| #include "src/contexts.h" |
| #include "src/isolate.h" |
| #include "src/unicode-cache.h" |
| #include "src/zone/zone.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| // Forward declarations. |
| class AstRawString; |
| class BackgroundCompileTask; |
| class JavaScriptFrame; |
| class OptimizedCompilationInfo; |
| class OptimizedCompilationJob; |
| class ParseInfo; |
| class Parser; |
| class ScriptData; |
| struct ScriptStreamingData; |
| class TimedHistogram; |
| class UnoptimizedCompilationInfo; |
| class UnoptimizedCompilationJob; |
| class WorkerThreadRuntimeCallStats; |
| |
| typedef std::forward_list<std::unique_ptr<UnoptimizedCompilationJob>> |
| UnoptimizedCompilationJobList; |
| |
| // The V8 compiler API. |
| // |
| // This is the central hub for dispatching to the various compilers within V8. |
| // Logic for which compiler to choose and how to wire compilation results into |
| // the object heap should be kept inside this class. |
| // |
| // General strategy: Scripts are translated into anonymous functions w/o |
| // parameters which then can be executed. If the source code contains other |
| // functions, they might be compiled and allocated as part of the compilation |
| // of the source code or deferred for lazy compilation at a later point. |
| class V8_EXPORT_PRIVATE Compiler : public AllStatic { |
| public: |
| enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION }; |
| |
| // =========================================================================== |
| // The following family of methods ensures a given function is compiled. The |
| // general contract is that failures will be reported by returning {false}, |
| // whereas successful compilation ensures the {is_compiled} predicate on the |
| // given function holds (except for live-edit, which compiles the world). |
| |
| static bool Compile(Handle<SharedFunctionInfo> shared, |
| ClearExceptionFlag flag); |
| static bool Compile(Handle<JSFunction> function, ClearExceptionFlag flag); |
| static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode); |
| |
| V8_WARN_UNUSED_RESULT static MaybeHandle<SharedFunctionInfo> |
| CompileForLiveEdit(ParseInfo* parse_info, Isolate* isolate); |
| |
| // Finalize and install code from previously run background compile task. |
| static bool FinalizeBackgroundCompileTask( |
| BackgroundCompileTask* task, Handle<SharedFunctionInfo> shared_info, |
| Isolate* isolate, ClearExceptionFlag flag); |
| |
| // Finalize and install optimized code from previously run job. |
| static bool FinalizeOptimizedCompilationJob(OptimizedCompilationJob* job, |
| Isolate* isolate); |
| |
| // Give the compiler a chance to perform low-latency initialization tasks of |
| // the given {function} on its instantiation. Note that only the runtime will |
| // offer this chance, optimized closure instantiation will not call this. |
| static void PostInstantiation(Handle<JSFunction> function, PretenureFlag); |
| |
| // Parser::Parse, then Compiler::Analyze. |
| static bool ParseAndAnalyze(ParseInfo* parse_info, |
| Handle<SharedFunctionInfo> shared_info, |
| Isolate* isolate); |
| // Rewrite and analyze scopes. |
| static bool Analyze(ParseInfo* parse_info); |
| |
| // =========================================================================== |
| // The following family of methods instantiates new functions for scripts or |
| // function literals. The decision whether those functions will be compiled, |
| // is left to the discretion of the compiler. |
| // |
| // Please note this interface returns shared function infos. This means you |
| // need to call Factory::NewFunctionFromSharedFunctionInfo before you have a |
| // real function with a context. |
| |
| // Create a (bound) function for a String source within a context for eval. |
| V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval( |
| Handle<String> source, Handle<SharedFunctionInfo> outer_info, |
| Handle<Context> context, LanguageMode language_mode, |
| ParseRestriction restriction, int parameters_end_pos, |
| int eval_scope_position, int eval_position); |
| |
| struct ScriptDetails { |
| ScriptDetails() : line_offset(0), column_offset(0) {} |
| explicit ScriptDetails(Handle<Object> script_name) |
| : line_offset(0), column_offset(0), name_obj(script_name) {} |
| |
| int line_offset; |
| int column_offset; |
| i::MaybeHandle<i::Object> name_obj; |
| i::MaybeHandle<i::Object> source_map_url; |
| i::MaybeHandle<i::FixedArray> host_defined_options; |
| }; |
| |
| // Create a function that results from wrapping |source| in a function, |
| // with |arguments| being a list of parameters for that function. |
| V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetWrappedFunction( |
| Handle<String> source, Handle<FixedArray> arguments, |
| Handle<Context> context, const ScriptDetails& script_details, |
| ScriptOriginOptions origin_options, ScriptData* cached_data, |
| v8::ScriptCompiler::CompileOptions compile_options, |
| v8::ScriptCompiler::NoCacheReason no_cache_reason); |
| |
| // Returns true if the embedder permits compiling the given source string in |
| // the given context. |
| static bool CodeGenerationFromStringsAllowed(Isolate* isolate, |
| Handle<Context> context, |
| Handle<String> source); |
| |
| // Create a (bound) function for a String source within a context for eval. |
| V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> GetFunctionFromString( |
| Handle<Context> context, Handle<String> source, |
| ParseRestriction restriction, int parameters_end_pos); |
| |
| // Create a shared function info object for a String source. |
| static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScript( |
| Isolate* isolate, Handle<String> source, |
| const ScriptDetails& script_details, ScriptOriginOptions origin_options, |
| v8::Extension* extension, ScriptData* cached_data, |
| ScriptCompiler::CompileOptions compile_options, |
| ScriptCompiler::NoCacheReason no_cache_reason, |
| NativesFlag is_natives_code); |
| |
| // Create a shared function info object for a Script source that has already |
| // been parsed and possibly compiled on a background thread while being loaded |
| // from a streamed source. On return, the data held by |streaming_data| will |
| // have been released, however the object itself isn't freed and is still |
| // owned by the caller. |
| static MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForStreamedScript( |
| Isolate* isolate, Handle<String> source, |
| const ScriptDetails& script_details, ScriptOriginOptions origin_options, |
| ScriptStreamingData* streaming_data); |
| |
| // Create a shared function info object for the given function literal |
| // node (the code may be lazily compiled). |
| static Handle<SharedFunctionInfo> GetSharedFunctionInfo(FunctionLiteral* node, |
| Handle<Script> script, |
| Isolate* isolate); |
| |
| // =========================================================================== |
| // The following family of methods provides support for OSR. Code generated |
| // for entry via OSR might not be suitable for normal entry, hence will be |
| // returned directly to the caller. |
| // |
| // Please note this interface is the only part dealing with {Code} objects |
| // directly. Other methods are agnostic to {Code} and can use an interpreter |
| // instead of generating JIT code for a function at all. |
| |
| // Generate and return optimized code for OSR, or empty handle on failure. |
| V8_WARN_UNUSED_RESULT static MaybeHandle<Code> GetOptimizedCodeForOSR( |
| Handle<JSFunction> function, BailoutId osr_offset, |
| JavaScriptFrame* osr_frame); |
| }; |
| |
| // A base class for compilation jobs intended to run concurrent to the main |
| // thread. The current state of the job can be checked using {state()}. |
| class V8_EXPORT_PRIVATE CompilationJob { |
| public: |
| enum Status { SUCCEEDED, FAILED }; |
| enum class State { |
| kReadyToPrepare, |
| kReadyToExecute, |
| kReadyToFinalize, |
| kSucceeded, |
| kFailed, |
| }; |
| |
| CompilationJob(uintptr_t stack_limit, State initial_state) |
| : state_(initial_state), stack_limit_(stack_limit) {} |
| virtual ~CompilationJob() = default; |
| |
| void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; } |
| uintptr_t stack_limit() const { return stack_limit_; } |
| |
| State state() const { return state_; } |
| |
| protected: |
| V8_WARN_UNUSED_RESULT Status UpdateState(Status status, State next_state) { |
| if (status == SUCCEEDED) { |
| state_ = next_state; |
| } else { |
| state_ = State::kFailed; |
| } |
| return status; |
| } |
| |
| private: |
| State state_; |
| uintptr_t stack_limit_; |
| }; |
| |
| // A base class for unoptimized compilation jobs. |
| // |
| // The job is split into two phases which are called in sequence on |
| // different threads and with different limitations: |
| // 1) ExecuteJob: Runs concurrently. No heap allocation or handle derefs. |
| // 2) FinalizeJob: Runs on main thread. No dependency changes. |
| // |
| // Either of phases can either fail or succeed. |
| class UnoptimizedCompilationJob : public CompilationJob { |
| public: |
| UnoptimizedCompilationJob(intptr_t stack_limit, ParseInfo* parse_info, |
| UnoptimizedCompilationInfo* compilation_info) |
| : CompilationJob(stack_limit, State::kReadyToExecute), |
| parse_info_(parse_info), |
| compilation_info_(compilation_info) {} |
| |
| // Executes the compile job. Can be called on a background thread. |
| V8_WARN_UNUSED_RESULT Status ExecuteJob(); |
| |
| // Finalizes the compile job. Must be called on the main thread. |
| V8_WARN_UNUSED_RESULT Status |
| FinalizeJob(Handle<SharedFunctionInfo> shared_info, Isolate* isolate); |
| |
| void RecordCompilationStats(Isolate* isolate) const; |
| void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag, |
| Handle<SharedFunctionInfo> shared, |
| Isolate* isolate) const; |
| |
| ParseInfo* parse_info() const { return parse_info_; } |
| UnoptimizedCompilationInfo* compilation_info() const { |
| return compilation_info_; |
| } |
| |
| protected: |
| // Overridden by the actual implementation. |
| virtual Status ExecuteJobImpl() = 0; |
| virtual Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info, |
| Isolate* isolate) = 0; |
| |
| private: |
| ParseInfo* parse_info_; |
| UnoptimizedCompilationInfo* compilation_info_; |
| base::TimeDelta time_taken_to_execute_; |
| base::TimeDelta time_taken_to_finalize_; |
| }; |
| |
| // A base class for optimized compilation jobs. |
| // |
| // The job is split into three phases which are called in sequence on |
| // different threads and with different limitations: |
| // 1) PrepareJob: Runs on main thread. No major limitations. |
| // 2) ExecuteJob: Runs concurrently. No heap allocation or handle derefs. |
| // 3) FinalizeJob: Runs on main thread. No dependency changes. |
| // |
| // Each of the three phases can either fail or succeed. |
| class OptimizedCompilationJob : public CompilationJob { |
| public: |
| OptimizedCompilationJob(uintptr_t stack_limit, |
| OptimizedCompilationInfo* compilation_info, |
| const char* compiler_name, |
| State initial_state = State::kReadyToPrepare) |
| : CompilationJob(stack_limit, initial_state), |
| compilation_info_(compilation_info), |
| compiler_name_(compiler_name) {} |
| |
| // Prepare the compile job. Must be called on the main thread. |
| V8_WARN_UNUSED_RESULT Status PrepareJob(Isolate* isolate); |
| |
| // Executes the compile job. Can be called on a background thread if |
| // can_execute_on_background_thread() returns true. |
| V8_WARN_UNUSED_RESULT Status ExecuteJob(); |
| |
| // Finalizes the compile job. Must be called on the main thread. |
| V8_WARN_UNUSED_RESULT Status FinalizeJob(Isolate* isolate); |
| |
| // Report a transient failure, try again next time. Should only be called on |
| // optimization compilation jobs. |
| Status RetryOptimization(BailoutReason reason); |
| |
| // Report a persistent failure, disable future optimization on the function. |
| // Should only be called on optimization compilation jobs. |
| Status AbortOptimization(BailoutReason reason); |
| |
| void RecordCompilationStats() const; |
| void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag, |
| Isolate* isolate) const; |
| |
| OptimizedCompilationInfo* compilation_info() const { |
| return compilation_info_; |
| } |
| |
| protected: |
| // Overridden by the actual implementation. |
| virtual Status PrepareJobImpl(Isolate* isolate) = 0; |
| virtual Status ExecuteJobImpl() = 0; |
| virtual Status FinalizeJobImpl(Isolate* isolate) = 0; |
| |
| private: |
| OptimizedCompilationInfo* compilation_info_; |
| base::TimeDelta time_taken_to_prepare_; |
| base::TimeDelta time_taken_to_execute_; |
| base::TimeDelta time_taken_to_finalize_; |
| const char* compiler_name_; |
| }; |
| |
| class V8_EXPORT_PRIVATE BackgroundCompileTask { |
| public: |
| // Creates a new task that when run will parse and compile the streamed |
| // script associated with |data| and can be finalized with |
| // Compiler::GetSharedFunctionInfoForStreamedScript. |
| // Note: does not take ownership of |data|. |
| BackgroundCompileTask(ScriptStreamingData* data, Isolate* isolate); |
| ~BackgroundCompileTask(); |
| |
| // Creates a new task that when run will parse and compile the |
| // |function_literal| and can be finalized with |
| // Compiler::FinalizeBackgroundCompileTask. |
| BackgroundCompileTask( |
| AccountingAllocator* allocator, const ParseInfo* outer_parse_info, |
| const AstRawString* function_name, |
| const FunctionLiteral* function_literal, |
| WorkerThreadRuntimeCallStats* worker_thread_runtime_stats, |
| TimedHistogram* timer, int max_stack_size); |
| |
| void Run(); |
| |
| ParseInfo* info() { return info_.get(); } |
| Parser* parser() { return parser_.get(); } |
| UnoptimizedCompilationJob* outer_function_job() { |
| return outer_function_job_.get(); |
| } |
| UnoptimizedCompilationJobList* inner_function_jobs() { |
| return &inner_function_jobs_; |
| } |
| |
| private: |
| // Data needed for parsing, and data needed to to be passed between thread |
| // between parsing and compilation. These need to be initialized before the |
| // compilation starts. |
| std::unique_ptr<ParseInfo> info_; |
| std::unique_ptr<Parser> parser_; |
| // TODO(rmcilroy): Consider having thread-local unicode-caches rather than |
| // creating a new one each time. |
| UnicodeCache unicode_cache_; |
| |
| // Data needed for finalizing compilation after background compilation. |
| std::unique_ptr<UnoptimizedCompilationJob> outer_function_job_; |
| UnoptimizedCompilationJobList inner_function_jobs_; |
| |
| int stack_size_; |
| WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats_; |
| AccountingAllocator* allocator_; |
| TimedHistogram* timer_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BackgroundCompileTask); |
| }; |
| |
| // Contains all data which needs to be transmitted between threads for |
| // background parsing and compiling and finalizing it on the main thread. |
| struct ScriptStreamingData { |
| ScriptStreamingData(ScriptCompiler::ExternalSourceStream* source_stream, |
| ScriptCompiler::StreamedSource::Encoding encoding); |
| ~ScriptStreamingData(); |
| |
| void Release(); |
| |
| // Internal implementation of v8::ScriptCompiler::StreamedSource. |
| std::unique_ptr<ScriptCompiler::ExternalSourceStream> source_stream; |
| ScriptCompiler::StreamedSource::Encoding encoding; |
| |
| // Task that performs background parsing and compilation. |
| std::unique_ptr<BackgroundCompileTask> task; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScriptStreamingData); |
| }; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_COMPILER_H_ |