| // 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 JavaScriptFrame; | |
| class OptimizedCompilationInfo; | |
| class OptimizedCompilationJob; | |
| class ParseInfo; | |
| class Parser; | |
| class ScriptData; | |
| struct ScriptStreamingData; | |
| class UnoptimizedCompilationInfo; | |
| class UnoptimizedCompilationJob; | |
| 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); | |
| // Creates a new task that when run will parse and compile the streamed | |
| // script associated with |streaming_data| and can be finalized with | |
| // Compiler::GetSharedFunctionInfoForStreamedScript. | |
| // Note: does not take ownership of streaming_data. | |
| static ScriptCompiler::ScriptStreamingTask* NewBackgroundCompileTask( | |
| ScriptStreamingData* streaming_data, Isolate* isolate); | |
| // Generate and install code from previously queued compilation job. | |
| static bool FinalizeCompilationJob(UnoptimizedCompilationJob* job, | |
| Handle<SharedFunctionInfo> shared_info, | |
| Isolate* isolate); | |
| static bool FinalizeCompilationJob(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, int line_offset = 0, | |
| int column_offset = 0, Handle<Object> script_name = Handle<Object>(), | |
| ScriptOriginOptions options = ScriptOriginOptions()); | |
| 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() {} | |
| 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_; | |
| }; | |
| // 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; | |
| std::unique_ptr<ScriptCompiler::CachedData> cached_data; | |
| // 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. | |
| UnicodeCache unicode_cache; | |
| std::unique_ptr<ParseInfo> info; | |
| std::unique_ptr<Parser> parser; | |
| // Data needed for finalizing compilation after background compilation. | |
| std::unique_ptr<UnoptimizedCompilationJob> outer_function_job; | |
| UnoptimizedCompilationJobList inner_function_jobs; | |
| DISALLOW_COPY_AND_ASSIGN(ScriptStreamingData); | |
| }; | |
| } // namespace internal | |
| } // namespace v8 | |
| #endif // V8_COMPILER_H_ |