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_LIBPLATFORM_V8_TRACING_H_
  #define V8_LIBPLATFORM_V8_TRACING_H_
  
  #include <fstream>
  #include <memory>
  #include <unordered_set>
  #include <vector>
  
  #include "libplatform-export.h"
  #include "v8-platform.h"  // NOLINT(build/include)
  
  namespace v8 {
  
  namespace base {
  class Mutex;
  }  // namespace base
  
  namespace platform {
  namespace tracing {
  
  const int kTraceMaxNumArgs = 2;
  
  class V8_PLATFORM_EXPORT TraceObject {
   public:
    union ArgValue {
      bool as_bool;
      uint64_t as_uint;
      int64_t as_int;
      double as_double;
      const void* as_pointer;
      const char* as_string;
    };
  
    TraceObject() {}
    ~TraceObject();
    void Initialize(
        char phase, const uint8_t* category_enabled_flag, const char* name,
        const char* scope, uint64_t id, uint64_t bind_id, int num_args,
        const char** arg_names, const uint8_t* arg_types,
        const uint64_t* arg_values,
        std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
        unsigned int flags);
    void UpdateDuration();
    void InitializeForTesting(
        char phase, const uint8_t* category_enabled_flag, const char* name,
        const char* scope, uint64_t id, uint64_t bind_id, int num_args,
        const char** arg_names, const uint8_t* arg_types,
        const uint64_t* arg_values,
        std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
        unsigned int flags, int pid, int tid, int64_t ts, int64_t tts,
        uint64_t duration, uint64_t cpu_duration);
  
    int pid() const { return pid_; }
    int tid() const { return tid_; }
    char phase() const { return phase_; }
    const uint8_t* category_enabled_flag() const {
      return category_enabled_flag_;
    }
    const char* name() const { return name_; }
    const char* scope() const { return scope_; }
    uint64_t id() const { return id_; }
    uint64_t bind_id() const { return bind_id_; }
    int num_args() const { return num_args_; }
    const char** arg_names() { return arg_names_; }
    uint8_t* arg_types() { return arg_types_; }
    ArgValue* arg_values() { return arg_values_; }
    std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables() {
      return arg_convertables_;
    }
    unsigned int flags() const { return flags_; }
    int64_t ts() { return ts_; }
    int64_t tts() { return tts_; }
    uint64_t duration() { return duration_; }
    uint64_t cpu_duration() { return cpu_duration_; }
  
   private:
    int pid_;
    int tid_;
    char phase_;
    const char* name_;
    const char* scope_;
    const uint8_t* category_enabled_flag_;
    uint64_t id_;
    uint64_t bind_id_;
    int num_args_ = 0;
    const char* arg_names_[kTraceMaxNumArgs];
    uint8_t arg_types_[kTraceMaxNumArgs];
    ArgValue arg_values_[kTraceMaxNumArgs];
    std::unique_ptr<v8::ConvertableToTraceFormat>
        arg_convertables_[kTraceMaxNumArgs];
    char* parameter_copy_storage_ = nullptr;
    unsigned int flags_;
    int64_t ts_;
    int64_t tts_;
    uint64_t duration_;
    uint64_t cpu_duration_;
  
    // Disallow copy and assign
    TraceObject(const TraceObject&) = delete;
    void operator=(const TraceObject&) = delete;
  };
  
  class V8_PLATFORM_EXPORT TraceWriter {
   public:
    TraceWriter() {}
    virtual ~TraceWriter() {}
    virtual void AppendTraceEvent(TraceObject* trace_event) = 0;
    virtual void Flush() = 0;
  
    static TraceWriter* CreateJSONTraceWriter(std::ostream& stream);
  
   private:
    // Disallow copy and assign
    TraceWriter(const TraceWriter&) = delete;
    void operator=(const TraceWriter&) = delete;
  };
  
  class V8_PLATFORM_EXPORT TraceBufferChunk {
   public:
    explicit TraceBufferChunk(uint32_t seq);
  
    void Reset(uint32_t new_seq);
    bool IsFull() const { return next_free_ == kChunkSize; }
    TraceObject* AddTraceEvent(size_t* event_index);
    TraceObject* GetEventAt(size_t index) { return &chunk_[index]; }
  
    uint32_t seq() const { return seq_; }
    size_t size() const { return next_free_; }
  
    static const size_t kChunkSize = 64;
  
   private:
    size_t next_free_ = 0;
    TraceObject chunk_[kChunkSize];
    uint32_t seq_;
  
    // Disallow copy and assign
    TraceBufferChunk(const TraceBufferChunk&) = delete;
    void operator=(const TraceBufferChunk&) = delete;
  };
  
  class V8_PLATFORM_EXPORT TraceBuffer {
   public:
    TraceBuffer() {}
    virtual ~TraceBuffer() {}
  
    virtual TraceObject* AddTraceEvent(uint64_t* handle) = 0;
    virtual TraceObject* GetEventByHandle(uint64_t handle) = 0;
    virtual bool Flush() = 0;
  
    static const size_t kRingBufferChunks = 1024;
  
    static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks,
                                                    TraceWriter* trace_writer);
  
   private:
    // Disallow copy and assign
    TraceBuffer(const TraceBuffer&) = delete;
    void operator=(const TraceBuffer&) = delete;
  };
  
  // Options determines how the trace buffer stores data.
  enum TraceRecordMode {
    // Record until the trace buffer is full.
    RECORD_UNTIL_FULL,
  
    // Record until the user ends the trace. The trace buffer is a fixed size
    // and we use it as a ring buffer during recording.
    RECORD_CONTINUOUSLY,
  
    // Record until the trace buffer is full, but with a huge buffer size.
    RECORD_AS_MUCH_AS_POSSIBLE,
  
    // Echo to console. Events are discarded.
    ECHO_TO_CONSOLE,
  };
  
  class V8_PLATFORM_EXPORT TraceConfig {
   public:
    typedef std::vector<std::string> StringList;
  
    static TraceConfig* CreateDefaultTraceConfig();
  
    TraceConfig() : enable_systrace_(false), enable_argument_filter_(false) {}
    TraceRecordMode GetTraceRecordMode() const { return record_mode_; }
    bool IsSystraceEnabled() const { return enable_systrace_; }
    bool IsArgumentFilterEnabled() const { return enable_argument_filter_; }
  
    void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; }
    void EnableSystrace() { enable_systrace_ = true; }
    void EnableArgumentFilter() { enable_argument_filter_ = true; }
  
    void AddIncludedCategory(const char* included_category);
  
    bool IsCategoryGroupEnabled(const char* category_group) const;
  
   private:
    TraceRecordMode record_mode_;
    bool enable_systrace_ : 1;
    bool enable_argument_filter_ : 1;
    StringList included_categories_;
  
    // Disallow copy and assign
    TraceConfig(const TraceConfig&) = delete;
    void operator=(const TraceConfig&) = delete;
  };
  
  #if defined(_MSC_VER)
  #define V8_PLATFORM_NON_EXPORTED_BASE(code) \
    __pragma(warning(suppress : 4275)) code
  #else
  #define V8_PLATFORM_NON_EXPORTED_BASE(code) code
  #endif  // defined(_MSC_VER)
  
  class V8_PLATFORM_EXPORT TracingController
      : public V8_PLATFORM_NON_EXPORTED_BASE(v8::TracingController) {
   public:
    enum Mode { DISABLED = 0, RECORDING_MODE };
  
    // The pointer returned from GetCategoryGroupEnabledInternal() points to a
    // value with zero or more of the following bits. Used in this class only.
    // The TRACE_EVENT macros should only use the value as a bool.
    // These values must be in sync with macro values in TraceEvent.h in Blink.
    enum CategoryGroupEnabledFlags {
      // Category group enabled for the recording mode.
      ENABLED_FOR_RECORDING = 1 << 0,
      // Category group enabled by SetEventCallbackEnabled().
      ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
      // Category group enabled to export events to ETW.
      ENABLED_FOR_ETW_EXPORT = 1 << 3
    };
  
    TracingController();
    ~TracingController() override;
    void Initialize(TraceBuffer* trace_buffer);
  
    // v8::TracingController implementation.
    const uint8_t* GetCategoryGroupEnabled(const char* category_group) override;
    uint64_t AddTraceEvent(
        char phase, const uint8_t* category_enabled_flag, const char* name,
        const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
        const char** arg_names, const uint8_t* arg_types,
        const uint64_t* arg_values,
        std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
        unsigned int flags) override;
    void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
                                  const char* name, uint64_t handle) override;
    void AddTraceStateObserver(
        v8::TracingController::TraceStateObserver* observer) override;
    void RemoveTraceStateObserver(
        v8::TracingController::TraceStateObserver* observer) override;
  
    void StartTracing(TraceConfig* trace_config);
    void StopTracing();
  
    static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag);
  
   private:
    const uint8_t* GetCategoryGroupEnabledInternal(const char* category_group);
    void UpdateCategoryGroupEnabledFlag(size_t category_index);
    void UpdateCategoryGroupEnabledFlags();
  
    std::unique_ptr<TraceBuffer> trace_buffer_;
    std::unique_ptr<TraceConfig> trace_config_;
    std::unique_ptr<base::Mutex> mutex_;
    std::unordered_set<v8::TracingController::TraceStateObserver*> observers_;
    Mode mode_ = DISABLED;
  
    // Disallow copy and assign
    TracingController(const TracingController&) = delete;
    void operator=(const TracingController&) = delete;
  };
  
  #undef V8_PLATFORM_NON_EXPORTED_BASE
  
  }  // namespace tracing
  }  // namespace platform
  }  // namespace v8
  
  #endif  // V8_LIBPLATFORM_V8_TRACING_H_
  