// 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/ast/ast-value-factory.h"
#include "src/base/platform/elapsed-timer.h"
#include "src/base/small-vector.h"
#include "src/codegen/background-merge-task.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/snapshot/code-serializer.h"
#include "src/utils/allocation.h"
#include "src/zone/zone.h"

namespace v8 {
namespace internal {

// Forward declarations.
class AlignedCachedData;
class BackgroundCompileTask;
class IsCompiledScope;
class OptimizedCompilationInfo;
class ParseInfo;
class RuntimeCallStats;
class TimedHistogram;
class TurbofanCompilationJob;
class UnoptimizedCompilationInfo;
class UnoptimizedCompilationJob;
class UnoptimizedFrame;
class WorkerThreadRuntimeCallStats;
struct ScriptDetails;
struct ScriptStreamingData;

namespace maglev {
class MaglevCompilationJob;
}  // namespace maglev

// 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(Isolate* isolate, Handle<SharedFunctionInfo> shared,
                      ClearExceptionFlag flag,
                      IsCompiledScope* is_compiled_scope,
                      CreateSourcePositions create_source_positions_flag =
                          CreateSourcePositions::kNo);
  static bool Compile(Isolate* isolate, Handle<JSFunction> function,
                      ClearExceptionFlag flag,
                      IsCompiledScope* is_compiled_scope);
  static MaybeHandle<SharedFunctionInfo> CompileToplevel(
      ParseInfo* parse_info, Handle<Script> script, Isolate* isolate,
      IsCompiledScope* is_compiled_scope);

  static bool CompileSharedWithBaseline(Isolate* isolate,
                                        Handle<SharedFunctionInfo> shared,
                                        ClearExceptionFlag flag,
                                        IsCompiledScope* is_compiled_scope);
  static bool CompileBaseline(Isolate* isolate, Handle<JSFunction> function,
                              ClearExceptionFlag flag,
                              IsCompiledScope* is_compiled_scope);

  static bool CompileMaglev(Isolate* isolate, Handle<JSFunction> function,
                            ConcurrencyMode mode,
                            IsCompiledScope* is_compiled_scope);

  static void CompileOptimized(Isolate* isolate, Handle<JSFunction> function,
                               ConcurrencyMode mode, CodeKind code_kind);

  // Generate and return optimized code for OSR. The empty handle is returned
  // either on failure, or after spawning a concurrent OSR task (in which case
  // a future OSR request will pick up the resulting code object).
  V8_WARN_UNUSED_RESULT static MaybeHandle<CodeT> CompileOptimizedOSR(
      Isolate* isolate, Handle<JSFunction> function, BytecodeOffset osr_offset,
      UnoptimizedFrame* frame, ConcurrencyMode mode);

  V8_WARN_UNUSED_RESULT static MaybeHandle<SharedFunctionInfo>
  CompileForLiveEdit(ParseInfo* parse_info, Handle<Script> script,
                     Isolate* isolate);

  // 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);

  // Finalize and install code from previously run background compile task.
  static bool FinalizeBackgroundCompileTask(BackgroundCompileTask* task,
                                            Isolate* isolate,
                                            ClearExceptionFlag flag);

  // Dispose a job without finalization.
  static void DisposeTurbofanCompilationJob(TurbofanCompilationJob* job,
                                            bool restore_function_code);

  // Finalize and install Turbofan code from a previously run job.
  static bool FinalizeTurbofanCompilationJob(TurbofanCompilationJob* job,
                                             Isolate* isolate);

  // Finalize and install Maglev code from a previously run job.
  static bool FinalizeMaglevCompilationJob(maglev::MaglevCompilationJob* 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,
      ParsingWhileDebugging parsing_while_debugging =
          ParsingWhileDebugging::kNo);

  // 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,
      AlignedCachedData* 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,
      ScriptCompiler::CompileOptions compile_options,
      ScriptCompiler::NoCacheReason no_cache_reason,
      NativesFlag is_natives_code);

  // Create a shared function info object for a String source.
  static MaybeHandle<SharedFunctionInfo>
  GetSharedFunctionInfoForScriptWithExtension(
      Isolate* isolate, Handle<String> source,
      const ScriptDetails& script_details, v8::Extension* extension,
      ScriptCompiler::CompileOptions compile_options,
      NativesFlag is_natives_code);

  // Create a shared function info object for a String source and serialized
  // cached data. The cached data may be rejected, in which case this function
  // will set cached_data->rejected() to true.
  static MaybeHandle<SharedFunctionInfo>
  GetSharedFunctionInfoForScriptWithCachedData(
      Isolate* isolate, Handle<String> source,
      const ScriptDetails& script_details, AlignedCachedData* cached_data,
      ScriptCompiler::CompileOptions compile_options,
      ScriptCompiler::NoCacheReason no_cache_reason,
      NativesFlag is_natives_code);

  // Create a shared function info object for a String source and a task that
  // has deserialized cached data on a background thread. The cached data from
  // the task may be rejected, in which case this function will set
  // deserialize_task->rejected() to true.
  static MaybeHandle<SharedFunctionInfo>
  GetSharedFunctionInfoForScriptWithDeserializeTask(
      Isolate* isolate, Handle<String> source,
      const ScriptDetails& script_details,
      BackgroundDeserializeTask* deserialize_task,
      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, ScriptStreamingData* streaming_data);

  static Handle<SharedFunctionInfo> GetSharedFunctionInfoForWebSnapshot(
      Isolate* isolate, Handle<String> source, MaybeHandle<Object> script_name);

  // Create a shared function info object for the given function literal
  // node (the code may be lazily compiled).
  template <typename IsolateT>
  static Handle<SharedFunctionInfo> GetSharedFunctionInfo(FunctionLiteral* node,
                                                          Handle<Script> script,
                                                          IsolateT* isolate);

  static void LogFunctionCompilation(Isolate* isolate,
                                     LogEventListener::CodeTag code_type,
                                     Handle<Script> script,
                                     Handle<SharedFunctionInfo> shared,
                                     Handle<FeedbackVector> vector,
                                     Handle<AbstractCode> abstract_code,
                                     CodeKind kind, double time_taken_ms);
};

// 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.
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(LogEventListener::CodeTag code_type,
                                 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.
class OptimizedCompilationJob : public CompilationJob {
 public:
  OptimizedCompilationJob(const char* compiler_name, State initial_state)
      : CompilationJob(initial_state), compiler_name_(compiler_name) {}

  // Prepare the compile job. Must be called on the main thread.
  V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Status PrepareJob(Isolate* isolate);

  // Executes the compile job. Can be called on a background thread.
  V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Status
  ExecuteJob(RuntimeCallStats* stats, LocalIsolate* local_isolate = nullptr);

  // Finalizes the compile job. Must be called on the main thread.
  V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT Status FinalizeJob(Isolate* isolate);

  const char* compiler_name() const { return compiler_name_; }

 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;

  base::TimeDelta time_taken_to_prepare_;
  base::TimeDelta time_taken_to_execute_;
  base::TimeDelta time_taken_to_finalize_;

 private:
  const char* const compiler_name_;
};

// Thin wrapper to split off Turbofan-specific parts.
class TurbofanCompilationJob : public OptimizedCompilationJob {
 public:
  TurbofanCompilationJob(OptimizedCompilationInfo* compilation_info,
                         State initial_state)
      : OptimizedCompilationJob("Turbofan", initial_state),
        compilation_info_(compilation_info) {}

  OptimizedCompilationInfo* compilation_info() const {
    return compilation_info_;
  }

  // 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(ConcurrencyMode mode, Isolate* isolate) const;
  void RecordFunctionCompilation(LogEventListener::CodeTag code_type,
                                 Isolate* isolate) const;

 private:
  OptimizedCompilationInfo* const compilation_info_;
};

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 V8_NODISCARD CompilationHandleScope final {
 public:
  explicit CompilationHandleScope(Isolate* isolate,
                                  OptimizedCompilationInfo* info)
      : persistent_(isolate), info_(info) {}
  V8_EXPORT_PRIVATE ~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 FinalizeScript.
  // Note: does not take ownership of |data|.
  BackgroundCompileTask(ScriptStreamingData* data, Isolate* isolate,
                        v8::ScriptType type,
                        ScriptCompiler::CompileOptions options);
  BackgroundCompileTask(const BackgroundCompileTask&) = delete;
  BackgroundCompileTask& operator=(const BackgroundCompileTask&) = delete;
  ~BackgroundCompileTask();

  // Creates a new task that when run will parse and compile the top-level
  // |shared_info| and can be finalized with FinalizeFunction in
  // Compiler::FinalizeBackgroundCompileTask.
  BackgroundCompileTask(
      Isolate* isolate, Handle<SharedFunctionInfo> shared_info,
      std::unique_ptr<Utf16CharacterStream> character_stream,
      WorkerThreadRuntimeCallStats* worker_thread_runtime_stats,
      TimedHistogram* timer, int max_stack_size);

  void Run();
  void RunOnMainThread(Isolate* isolate);
  void Run(LocalIsolate* isolate,
           ReusableUnoptimizedCompileState* reusable_state);

  // Checks the Isolate compilation cache to see whether it will be necessary to
  // merge the newly compiled objects into an existing Script. This can change
  // the value of ShouldMergeWithExistingScript, and embedders should check the
  // latter after calling this. May only be called on a thread where the Isolate
  // is currently entered.
  void SourceTextAvailable(Isolate* isolate, Handle<String> source_text,
                           const ScriptDetails& script_details);

  // Returns whether the embedder should call MergeWithExistingScript. This
  // function may be called from any thread, any number of times, but its return
  // value is only meaningful after SourceTextAvailable has completed.
  bool ShouldMergeWithExistingScript() const;

  // Partially merges newly compiled objects into an existing Script with the
  // same source, and generates a list of follow-up work for the main thread.
  // May be called from any thread, only once, and only if
  // ShouldMergeWithExistingScript returned true.
  void MergeWithExistingScript();

  MaybeHandle<SharedFunctionInfo> FinalizeScript(
      Isolate* isolate, Handle<String> source,
      const ScriptDetails& script_details);

  bool FinalizeFunction(Isolate* isolate, Compiler::ClearExceptionFlag flag);

  void AbortFunction();

  UnoptimizedCompileFlags flags() const { return flags_; }

 private:
  void ReportStatistics(Isolate* isolate);

  void ClearFunctionJobPointer();

  // Data needed for parsing and compilation. These need to be initialized
  // before the compilation starts.
  Isolate* isolate_for_local_isolate_;
  UnoptimizedCompileFlags flags_;
  UnoptimizedCompileState compile_state_;
  std::unique_ptr<Utf16CharacterStream> character_stream_;
  int stack_size_;
  WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats_;
  TimedHistogram* timer_;

  // Data needed for merging onto the main thread after background finalization.
  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_;
  base::SmallVector<v8::Isolate::UseCounterFeature, 8> use_counts_;
  int total_preparse_skipped_ = 0;

  // Single function data for top-level function compilation.
  MaybeHandle<SharedFunctionInfo> input_shared_info_;
  int start_position_;
  int end_position_;
  int function_literal_id_;

  // Task that merges newly compiled content into an existing Script from the
  // Isolate compilation cache, if necessary.
  BackgroundMergeTask background_merge_task_;
};

// 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(const ScriptStreamingData&) = delete;
  ScriptStreamingData& operator=(const ScriptStreamingData&) = delete;
  ~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;
};

class V8_EXPORT_PRIVATE BackgroundDeserializeTask {
 public:
  BackgroundDeserializeTask(Isolate* isolate,
                            std::unique_ptr<ScriptCompiler::CachedData> data);

  void Run();

  // Checks the Isolate compilation cache to see whether it will be necessary to
  // merge the newly deserialized objects into an existing Script. This can
  // change the value of ShouldMergeWithExistingScript, and embedders should
  // check the latter after calling this. May only be called on a thread where
  // the Isolate is currently entered.
  void SourceTextAvailable(Isolate* isolate, Handle<String> source_text,
                           const ScriptDetails& script_details);

  // Returns whether the embedder should call MergeWithExistingScript. This
  // function may be called from any thread, any number of times, but its return
  // value is only meaningful after SourceTextAvailable has completed.
  bool ShouldMergeWithExistingScript() const;

  // Partially merges newly deserialized objects into an existing Script with
  // the same source, as provided by SourceTextAvailable, and generates a list
  // of follow-up work for the main thread. May be called from any thread, only
  // once.
  void MergeWithExistingScript();

  MaybeHandle<SharedFunctionInfo> Finish(Isolate* isolate,
                                         Handle<String> source,
                                         ScriptOriginOptions origin_options);

  bool rejected() const { return cached_data_.rejected(); }

 private:
  Isolate* isolate_for_local_isolate_;
  AlignedCachedData cached_data_;
  CodeSerializer::OffThreadDeserializeData off_thread_data_;
  BackgroundMergeTask background_merge_task_;
};

}  // namespace internal
}  // namespace v8

#endif  // V8_CODEGEN_COMPILER_H_