text: // 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_CODEGEN_COMPILER_H_
  #define V8_CODEGEN_COMPILER_H_
  
  #include <forward_list>
  #include <memory>
  
  #include "src/base/platform/elapsed-timer.h"
  #include "src/codegen/bailout-reason.h"
  #include "src/common/globals.h"
  #include "src/execution/isolate.h"
  #include "src/execution/local-isolate.h"
  #include "src/handles/persistent-handles.h"
  #include "src/logging/code-events.h"
  #include "src/objects/contexts.h"
  #include "src/objects/debug-objects.h"
  #include "src/parsing/parse-info.h"
  #include "src/parsing/pending-compilation-error-handler.h"
  #include "src/utils/allocation.h"
  #include "src/zone/zone.h"
  
  namespace v8 {
  namespace internal {
  
  // Forward declarations.
  class AstRawString;
  class BackgroundCompileTask;
  class IsCompiledScope;
  class JavaScriptFrame;
  class OptimizedCompilationInfo;
  class OptimizedCompilationJob;
  class ParseInfo;
  class Parser;
  class RuntimeCallStats;
  class ScriptData;
  struct ScriptStreamingData;
  class TimedHistogram;
  class UnoptimizedCompilationInfo;
  class UnoptimizedCompilationJob;
  class WorkerThreadRuntimeCallStats;
  
  using UnoptimizedCompilationJobList =
      std::forward_list<std::unique_ptr<UnoptimizedCompilationJob>>;
  
  // 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,
                        IsCompiledScope* is_compiled_scope);
    static bool Compile(Handle<JSFunction> function, ClearExceptionFlag flag,
                        IsCompiledScope* is_compiled_scope);
    static bool CompileOptimized(Handle<JSFunction> function,
                                 ConcurrencyMode mode, CodeKind code_kind);
  
    // Collect source positions for a function that has already been compiled to
    // bytecode, but for which source positions were not collected (e.g. because
    // they were not immediately needed).
    static bool CollectSourcePositions(Isolate* isolate,
                                       Handle<SharedFunctionInfo> shared);
  
    V8_WARN_UNUSED_RESULT static MaybeHandle<SharedFunctionInfo>
    CompileForLiveEdit(ParseInfo* parse_info, Handle<Script> script,
                       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);
  
    // ===========================================================================
    // 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), repl_mode(REPLMode::kNo) {}
      explicit ScriptDetails(Handle<Object> script_name)
          : line_offset(0),
            column_offset(0),
            name_obj(script_name),
            repl_mode(REPLMode::kNo) {}
  
      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;
      REPLMode repl_mode;
    };
  
    // 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);
  
    // 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<i::Object> source,
        ParseRestriction restriction, int parameters_end_pos, bool is_code_like);
  
    // Decompose GetFunctionFromString into two functions, to allow callers to
    // deal seperately with a case of object not handled by the embedder.
    V8_WARN_UNUSED_RESULT static std::pair<MaybeHandle<String>, bool>
    ValidateDynamicCompilationSource(Isolate* isolate, Handle<Context> context,
                                     Handle<i::Object> source_object,
                                     bool is_code_like = false);
    V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction>
    GetFunctionFromValidatedString(Handle<Context> context,
                                   MaybeHandle<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).
    template <typename LocalIsolate>
    static Handle<SharedFunctionInfo> GetSharedFunctionInfo(
        FunctionLiteral* node, Handle<Script> script, LocalIsolate* 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, RETRY_ON_MAIN_THREAD };
    enum class State {
      kReadyToPrepare,
      kReadyToExecute,
      kReadyToFinalize,
      kSucceeded,
      kFailed,
    };
  
    explicit CompilationJob(State initial_state) : state_(initial_state) {
      timer_.Start();
    }
    virtual ~CompilationJob() = default;
  
    State state() const { return state_; }
  
   protected:
    V8_WARN_UNUSED_RESULT base::TimeDelta ElapsedTime() const {
      return timer_.Elapsed();
    }
  
    V8_WARN_UNUSED_RESULT Status UpdateState(Status status, State next_state) {
      switch (status) {
        case SUCCEEDED:
          state_ = next_state;
          break;
        case FAILED:
          state_ = State::kFailed;
          break;
        case RETRY_ON_MAIN_THREAD:
          // Don't change the state, we'll re-try on the main thread.
          break;
      }
      return status;
    }
  
   private:
    State state_;
    base::ElapsedTimer timer_;
  };
  
  // 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.
  // 未优化的编译作业, 分成按顺序调用的两步:
  // 1) 执行作业: 并行运行
  // 2) 完成作业
  // 任一步骤都会失败
  class UnoptimizedCompilationJob : public CompilationJob {
   public:
    UnoptimizedCompilationJob(uintptr_t stack_limit, ParseInfo* parse_info,
                              UnoptimizedCompilationInfo* compilation_info)
        : CompilationJob(State::kReadyToExecute),
          stack_limit_(stack_limit),
          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);
  
    // Finalizes the compile job. Can be called on a background thread, and might
    // return RETRY_ON_MAIN_THREAD if the finalization can't be run on the
    // background thread, and should instead be retried on the foreground thread.
    V8_WARN_UNUSED_RESULT Status
    FinalizeJob(Handle<SharedFunctionInfo> shared_info, LocalIsolate* isolate);
  
    void RecordCompilationStats(Isolate* isolate) const;
    void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
                                   Handle<SharedFunctionInfo> shared,
                                   Isolate* isolate) const;
  
    ParseInfo* parse_info() const {
      DCHECK_NOT_NULL(parse_info_);
      return parse_info_;
    }
    UnoptimizedCompilationInfo* compilation_info() const {
      return compilation_info_;
    }
  
    uintptr_t stack_limit() const { return stack_limit_; }
  
    base::TimeDelta time_taken_to_execute() const {
      return time_taken_to_execute_;
    }
    base::TimeDelta time_taken_to_finalize() const {
      return time_taken_to_finalize_;
    }
  
    void ClearParseInfo() { parse_info_ = nullptr; }
  
   protected:
    // Overridden by the actual implementation.
    virtual Status ExecuteJobImpl() = 0;
    virtual Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info,
                                   Isolate* isolate) = 0;
    virtual Status FinalizeJobImpl(Handle<SharedFunctionInfo> shared_info,
                                   LocalIsolate* isolate) = 0;
  
   private:
    uintptr_t stack_limit_;
    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.
  // 优化后编译作业, 分成顺序执行的三步:
  // 1) 准备作业: 主线程运行
  // 2) 执行作业: 可以并行运行
  // 3) 完成作业: 主线程运行
  class OptimizedCompilationJob : public CompilationJob {
   public:
    OptimizedCompilationJob(OptimizedCompilationInfo* compilation_info,
                            const char* compiler_name,
                            State initial_state = State::kReadyToPrepare)
        : CompilationJob(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(RuntimeCallStats* stats, LocalIsolate* local_isolate = nullptr);
  
    // 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);
  
    enum CompilationMode { kConcurrent, kSynchronous };
    void RecordCompilationStats(CompilationMode mode, Isolate* isolate) 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(RuntimeCallStats* stats,
                                  LocalIsolate* local_heap) = 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 FinalizeUnoptimizedCompilationData {
   public:
    FinalizeUnoptimizedCompilationData(Isolate* isolate,
                                       Handle<SharedFunctionInfo> function_handle,
                                       MaybeHandle<CoverageInfo> coverage_info,
                                       base::TimeDelta time_taken_to_execute,
                                       base::TimeDelta time_taken_to_finalize)
        : time_taken_to_execute_(time_taken_to_execute),
          time_taken_to_finalize_(time_taken_to_finalize),
          function_handle_(function_handle),
          coverage_info_(coverage_info) {}
  
    FinalizeUnoptimizedCompilationData(LocalIsolate* isolate,
                                       Handle<SharedFunctionInfo> function_handle,
                                       MaybeHandle<CoverageInfo> coverage_info,
                                       base::TimeDelta time_taken_to_execute,
                                       base::TimeDelta time_taken_to_finalize);
  
    Handle<SharedFunctionInfo> function_handle() const {
      return function_handle_;
    }
  
    MaybeHandle<CoverageInfo> coverage_info() const { return coverage_info_; }
  
    base::TimeDelta time_taken_to_execute() const {
      return time_taken_to_execute_;
    }
    base::TimeDelta time_taken_to_finalize() const {
      return time_taken_to_finalize_;
    }
  
   private:
    base::TimeDelta time_taken_to_execute_;
    base::TimeDelta time_taken_to_finalize_;
    Handle<SharedFunctionInfo> function_handle_;
    MaybeHandle<CoverageInfo> coverage_info_;
  };
  
  using FinalizeUnoptimizedCompilationDataList =
      std::vector<FinalizeUnoptimizedCompilationData>;
  
  class DeferredFinalizationJobData {
   public:
    DeferredFinalizationJobData(Isolate* isolate,
                                Handle<SharedFunctionInfo> function_handle,
                                std::unique_ptr<UnoptimizedCompilationJob> job) {
      UNREACHABLE();
    }
    DeferredFinalizationJobData(LocalIsolate* isolate,
                                Handle<SharedFunctionInfo> function_handle,
                                std::unique_ptr<UnoptimizedCompilationJob> job);
  
    Handle<SharedFunctionInfo> function_handle() const {
      return function_handle_;
    }
  
    UnoptimizedCompilationJob* job() const { return job_.get(); }
  
   private:
    Handle<SharedFunctionInfo> function_handle_;
    std::unique_ptr<UnoptimizedCompilationJob> job_;
  };
  
  // A wrapper around a OptimizedCompilationInfo that detaches the Handles from
  // the underlying PersistentHandlesScope and stores them in info_ on
  // destruction.
  class CompilationHandleScope final {
   public:
    explicit CompilationHandleScope(Isolate* isolate,
                                    OptimizedCompilationInfo* info)
        : persistent_(isolate), info_(info) {}
    ~CompilationHandleScope();
  
   private:
    PersistentHandlesScope persistent_;
    OptimizedCompilationInfo* info_;
  };
  
  using DeferredFinalizationJobDataList =
      std::vector<DeferredFinalizationJobData>;
  
  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(
        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() {
      DCHECK_NOT_NULL(info_);
      return info_.get();
    }
    Parser* parser() { return parser_.get(); }
    UnoptimizedCompilationJobList* compilation_jobs() {
      return &compilation_jobs_;
    }
    UnoptimizedCompileFlags flags() const { return flags_; }
    UnoptimizedCompileState* compile_state() { return &compile_state_; }
    LanguageMode language_mode() { return language_mode_; }
    FinalizeUnoptimizedCompilationDataList*
    finalize_unoptimized_compilation_data() {
      return &finalize_unoptimized_compilation_data_;
    }
  
    // Jobs which could not be finalized in the background task, and need to be
    // finalized on the main thread.
    DeferredFinalizationJobDataList* jobs_to_retry_finalization_on_main_thread() {
      return &jobs_to_retry_finalization_on_main_thread_;
    }
  
    // Getters for the off-thread finalization results, that create main-thread
    // handles to the objects.
    MaybeHandle<SharedFunctionInfo> GetOuterFunctionSfi(Isolate* isolate);
    Handle<Script> GetScript(Isolate* isolate);
  
   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.
    UnoptimizedCompileFlags flags_;
    UnoptimizedCompileState compile_state_;
    std::unique_ptr<ParseInfo> info_;
    std::unique_ptr<Parser> parser_;
  
    // Data needed for finalizing compilation after background compilation.
    UnoptimizedCompilationJobList compilation_jobs_;
  
    // Data needed for merging onto the main thread after background finalization.
    // TODO(leszeks): When these are available, the above fields are not. We
    // should add some stricter type-safety or DCHECKs to ensure that the user of
    // the task knows this.
    Isolate* isolate_for_local_isolate_;
    std::unique_ptr<PersistentHandles> persistent_handles_;
    MaybeHandle<SharedFunctionInfo> outer_function_sfi_;
    Handle<Script> script_;
    IsCompiledScope is_compiled_scope_;
    FinalizeUnoptimizedCompilationDataList finalize_unoptimized_compilation_data_;
    DeferredFinalizationJobDataList jobs_to_retry_finalization_on_main_thread_;
  
    // Single function data for top-level function compilation.
    int start_position_;
    int end_position_;
    int function_literal_id_;
  
    int stack_size_;
    WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats_;
    TimedHistogram* timer_;
    LanguageMode language_mode_;
  
    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(
        std::unique_ptr<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_CODEGEN_COMPILER_H_
  