text: // Copyright 2016 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_OPTIMIZED_COMPILATION_INFO_H_
  #define V8_CODEGEN_OPTIMIZED_COMPILATION_INFO_H_
  
  #include <memory>
  
  #include "src/base/vector.h"
  #include "src/codegen/bailout-reason.h"
  #include "src/codegen/source-position-table.h"
  #include "src/codegen/tick-counter.h"
  #include "src/common/globals.h"
  #include "src/diagnostics/basic-block-profiler.h"
  #include "src/execution/frames.h"
  #include "src/handles/handles.h"
  #include "src/handles/persistent-handles.h"
  #include "src/objects/objects.h"
  #include "src/utils/identity-map.h"
  #include "src/utils/utils.h"
  
  namespace v8 {
  
  namespace tracing {
  class TracedValue;
  }  // namespace tracing
  
  namespace internal {
  
  class FunctionLiteral;
  class Isolate;
  class JavaScriptFrame;
  class JSGlobalObject;
  class Zone;
  
  namespace compiler {
  class NodeObserver;
  }
  
  namespace wasm {
  struct WasmCompilationResult;
  }  // namespace wasm
  
  // OptimizedCompilationInfo encapsulates the information needed to compile
  // optimized code for a given function, and the results of the optimized
  // compilation.
  class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
   public:
    // Various configuration flags for a compilation, as well as some properties
    // of the compiled code produced by a compilation.
  
  #define FLAGS(V)                                                     \
    V(FunctionContextSpecializing, function_context_specializing, 0)   \
    V(Inlining, inlining, 1)                                           \
    V(DisableFutureOptimization, disable_future_optimization, 2)       \
    V(Splitting, splitting, 3)                                         \
    V(SourcePositions, source_positions, 4)                            \
    V(BailoutOnUninitialized, bailout_on_uninitialized, 5)             \
    V(LoopPeeling, loop_peeling, 6)                                    \
    V(UntrustedCodeMitigations, untrusted_code_mitigations, 7)         \
    V(SwitchJumpTable, switch_jump_table, 8)                           \
    V(CalledWithCodeStartRegister, called_with_code_start_register, 9) \
    V(PoisonRegisterArguments, poison_register_arguments, 10)          \
    V(AllocationFolding, allocation_folding, 11)                       \
    V(AnalyzeEnvironmentLiveness, analyze_environment_liveness, 12)    \
    V(TraceTurboJson, trace_turbo_json, 13)                            \
    V(TraceTurboGraph, trace_turbo_graph, 14)                          \
    V(TraceTurboScheduled, trace_turbo_scheduled, 15)                  \
    V(TraceTurboAllocation, trace_turbo_allocation, 16)                \
    V(TraceHeapBroker, trace_heap_broker, 17)                          \
    V(WasmRuntimeExceptionSupport, wasm_runtime_exception_support, 18) \
    V(ConcurrentInlining, concurrent_inlining, 19)                     \
    V(DiscardResultForTesting, discard_result_for_testing, 20)         \
    V(InlineJSWasmCalls, inline_js_wasm_calls, 21)
  
    enum Flag {
  #define DEF_ENUM(Camel, Lower, Bit) k##Camel = 1 << Bit,
      FLAGS(DEF_ENUM)
  #undef DEF_ENUM
    };
  
  #define DEF_GETTER(Camel, Lower, Bit) \
    bool Lower() const {                \
      DCHECK(FlagGetIsValid(k##Camel)); \
      return GetFlag(k##Camel);         \
    }
    FLAGS(DEF_GETTER)
  #undef DEF_GETTER
  
  #define DEF_SETTER(Camel, Lower, Bit) \
    void set_##Lower() {                \
      DCHECK(FlagSetIsValid(k##Camel)); \
      SetFlag(k##Camel);                \
    }
    FLAGS(DEF_SETTER)
  #undef DEF_SETTER
  
  #ifdef DEBUG
    bool FlagGetIsValid(Flag flag) const;
    bool FlagSetIsValid(Flag flag) const;
  #endif  // DEBUG
  
    // Construct a compilation info for optimized compilation.
    OptimizedCompilationInfo(Zone* zone, Isolate* isolate,
                             Handle<SharedFunctionInfo> shared,
                             Handle<JSFunction> closure, CodeKind code_kind,
                             BytecodeOffset osr_offset,
                             JavaScriptFrame* osr_frame);
    // For testing.
    OptimizedCompilationInfo(Zone* zone, Isolate* isolate,
                             Handle<SharedFunctionInfo> shared,
                             Handle<JSFunction> closure, CodeKind code_kind)
        : OptimizedCompilationInfo(zone, isolate, shared, closure, code_kind,
                                   BytecodeOffset::None(), nullptr) {}
    // Construct a compilation info for stub compilation, Wasm, and testing.
    OptimizedCompilationInfo(base::Vector<const char> debug_name, Zone* zone,
                             CodeKind code_kind);
  
    OptimizedCompilationInfo(const OptimizedCompilationInfo&) = delete;
    OptimizedCompilationInfo& operator=(const OptimizedCompilationInfo&) = delete;
  
    ~OptimizedCompilationInfo();
  
    Zone* zone() { return zone_; }
    bool is_osr() const { return !osr_offset_.IsNone(); }
    Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
    bool has_shared_info() const { return !shared_info().is_null(); }
    Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
    bool has_bytecode_array() const { return !bytecode_array_.is_null(); }
    Handle<JSFunction> closure() const { return closure_; }
    Handle<Code> code() const { return code_; }
    CodeKind code_kind() const { return code_kind_; }
    Builtin builtin() const { return builtin_; }
    void set_builtin(Builtin builtin) { builtin_ = builtin; }
    BytecodeOffset osr_offset() const { return osr_offset_; }
    JavaScriptFrame* osr_frame() const { return osr_frame_; }
    void SetNodeObserver(compiler::NodeObserver* observer) {
      DCHECK_NULL(node_observer_);
      node_observer_ = observer;
    }
    compiler::NodeObserver* node_observer() const { return node_observer_; }
  
    void SetPoisoningMitigationLevel(PoisoningMitigationLevel poisoning_level) {
      poisoning_level_ = poisoning_level;
    }
    PoisoningMitigationLevel GetPoisoningMitigationLevel() const {
      return poisoning_level_;
    }
  
    // Code getters and setters.
  
    void SetCode(Handle<Code> code);
  
  #if V8_ENABLE_WEBASSEMBLY
    void SetWasmCompilationResult(std::unique_ptr<wasm::WasmCompilationResult>);
    std::unique_ptr<wasm::WasmCompilationResult> ReleaseWasmCompilationResult();
  #endif  // V8_ENABLE_WEBASSEMBLY
  
    bool has_context() const;
    Context context() const;
  
    bool has_native_context() const;
    NativeContext native_context() const;
  
    bool has_global_object() const;
    JSGlobalObject global_object() const;
  
    // Accessors for the different compilation modes.
    bool IsOptimizing() const {
      return CodeKindIsOptimizedJSFunction(code_kind());
    }
    bool IsTurboprop() const { return code_kind() == CodeKind::TURBOPROP; }
  #if V8_ENABLE_WEBASSEMBLY
    bool IsWasm() const { return code_kind() == CodeKind::WASM_FUNCTION; }
  #endif  // V8_ENABLE_WEBASSEMBLY
  
    void set_persistent_handles(
        std::unique_ptr<PersistentHandles> persistent_handles) {
      DCHECK_NULL(ph_);
      ph_ = std::move(persistent_handles);
      DCHECK_NOT_NULL(ph_);
    }
  
    void set_canonical_handles(
        std::unique_ptr<CanonicalHandlesMap> canonical_handles) {
      DCHECK_NULL(canonical_handles_);
      canonical_handles_ = std::move(canonical_handles);
      DCHECK_NOT_NULL(canonical_handles_);
    }
  
    void ReopenHandlesInNewHandleScope(Isolate* isolate);
  
    void AbortOptimization(BailoutReason reason);
  
    void RetryOptimization(BailoutReason reason);
  
    BailoutReason bailout_reason() const { return bailout_reason_; }
  
    int optimization_id() const {
      DCHECK(IsOptimizing());
      return optimization_id_;
    }
  
    unsigned inlined_bytecode_size() const { return inlined_bytecode_size_; }
  
    void set_inlined_bytecode_size(unsigned size) {
      inlined_bytecode_size_ = size;
    }
  
    struct InlinedFunctionHolder {
      Handle<SharedFunctionInfo> shared_info;
      Handle<BytecodeArray> bytecode_array;  // Explicit to prevent flushing.
      InliningPosition position;
  
      InlinedFunctionHolder(Handle<SharedFunctionInfo> inlined_shared_info,
                            Handle<BytecodeArray> inlined_bytecode,
                            SourcePosition pos);
  
      void RegisterInlinedFunctionId(size_t inlined_function_id) {
        position.inlined_function_id = static_cast<int>(inlined_function_id);
      }
    };
  
    using InlinedFunctionList = std::vector<InlinedFunctionHolder>;
    InlinedFunctionList& inlined_functions() { return inlined_functions_; }
  
    // Returns the inlining id for source position tracking.
    int AddInlinedFunction(Handle<SharedFunctionInfo> inlined_function,
                           Handle<BytecodeArray> inlined_bytecode,
                           SourcePosition pos);
  
    std::unique_ptr<char[]> GetDebugName() const;
  
    StackFrame::Type GetOutputStackFrameType() const;
  
    const char* trace_turbo_filename() const {
      return trace_turbo_filename_.get();
    }
  
    void set_trace_turbo_filename(std::unique_ptr<char[]> filename) {
      trace_turbo_filename_ = std::move(filename);
    }
  
    TickCounter& tick_counter() { return tick_counter_; }
  
    BasicBlockProfilerData* profiler_data() const { return profiler_data_; }
    void set_profiler_data(BasicBlockProfilerData* profiler_data) {
      profiler_data_ = profiler_data;
    }
  
    std::unique_ptr<PersistentHandles> DetachPersistentHandles() {
      DCHECK_NOT_NULL(ph_);
      return std::move(ph_);
    }
  
    std::unique_ptr<CanonicalHandlesMap> DetachCanonicalHandles() {
      DCHECK_NOT_NULL(canonical_handles_);
      return std::move(canonical_handles_);
    }
  
   private:
    void ConfigureFlags();
  
    void SetFlag(Flag flag) { flags_ |= flag; }
    bool GetFlag(Flag flag) const { return (flags_ & flag) != 0; }
  
    void SetTracingFlags(bool passes_filter);
  
    // Compilation flags.
    unsigned flags_ = 0;
    PoisoningMitigationLevel poisoning_level_ =
        PoisoningMitigationLevel::kDontPoison;
  
    const CodeKind code_kind_;
    Builtin builtin_ = Builtin::kNoBuiltinId;
  
    // We retain a reference the bytecode array specifically to ensure it doesn't
    // get flushed while we are optimizing the code.
    Handle<BytecodeArray> bytecode_array_;
    Handle<SharedFunctionInfo> shared_info_;
    Handle<JSFunction> closure_;
  
    // The compiled code.
    Handle<Code> code_;
  
    // Basic block profiling support.
    BasicBlockProfilerData* profiler_data_ = nullptr;
  
  #if V8_ENABLE_WEBASSEMBLY
    // The WebAssembly compilation result, not published in the NativeModule yet.
    std::unique_ptr<wasm::WasmCompilationResult> wasm_compilation_result_;
  #endif  // V8_ENABLE_WEBASSEMBLY
  
    // Entry point when compiling for OSR, {BytecodeOffset::None} otherwise.
    const BytecodeOffset osr_offset_ = BytecodeOffset::None();
    // The current OSR frame for specialization or {nullptr}.
    JavaScriptFrame* const osr_frame_ = nullptr;
  
    // The zone from which the compilation pipeline working on this
    // OptimizedCompilationInfo allocates.
    Zone* const zone_;
  
    compiler::NodeObserver* node_observer_ = nullptr;
  
    BailoutReason bailout_reason_ = BailoutReason::kNoReason;
  
    InlinedFunctionList inlined_functions_;
  
    static constexpr int kNoOptimizationId = -1;
    const int optimization_id_;
    unsigned inlined_bytecode_size_ = 0;
  
    base::Vector<const char> debug_name_;
    std::unique_ptr<char[]> trace_turbo_filename_;
  
    TickCounter tick_counter_;
  
    // 1) PersistentHandles created via PersistentHandlesScope inside of
    //    CompilationHandleScope
    // 2) Owned by OptimizedCompilationInfo
    // 3) Owned by the broker's LocalHeap when entering the LocalHeapScope.
    // 4) Back to OptimizedCompilationInfo when exiting the LocalHeapScope.
    //
    // In normal execution it gets destroyed when PipelineData gets destroyed.
    // There is a special case in GenerateCodeForTesting where the JSHeapBroker
    // will not be retired in that same method. In this case, we need to re-attach
    // the PersistentHandles container to the JSHeapBroker.
    std::unique_ptr<PersistentHandles> ph_;
  
    // Canonical handles follow the same path as described by the persistent
    // handles above. The only difference is that is created in the
    // CanonicalHandleScope(i.e step 1) is different).
    std::unique_ptr<CanonicalHandlesMap> canonical_handles_;
  };
  
  }  // namespace internal
  }  // namespace v8
  
  #endif  // V8_CODEGEN_OPTIMIZED_COMPILATION_INFO_H_
  