// Copyright 2015 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_PROFILER_SAMPLING_HEAP_PROFILER_H_
#define V8_PROFILER_SAMPLING_HEAP_PROFILER_H_

#include <deque>
#include <map>
#include <memory>
#include <unordered_map>

#include "include/v8-profiler.h"
#include "src/heap/heap.h"
#include "src/profiler/strings-storage.h"

namespace v8 {

namespace base {
class RandomNumberGenerator;
}

namespace internal {

class SamplingAllocationObserver;

class AllocationProfile : public v8::AllocationProfile {
 public:
  AllocationProfile() = default;

  v8::AllocationProfile::Node* GetRootNode() override {
    return nodes_.size() == 0 ? nullptr : &nodes_.front();
  }

  const std::vector<v8::AllocationProfile::Sample>& GetSamples() override {
    return samples_;
  }

 private:
  std::deque<v8::AllocationProfile::Node> nodes_;
  std::vector<v8::AllocationProfile::Sample> samples_;

  friend class SamplingHeapProfiler;

  DISALLOW_COPY_AND_ASSIGN(AllocationProfile);
};

class SamplingHeapProfiler {
 public:
  class AllocationNode {
   public:
    using FunctionId = uint64_t;
    AllocationNode(AllocationNode* parent, const char* name, int script_id,
                   int start_position, uint32_t id)
        : parent_(parent),
          script_id_(script_id),
          script_position_(start_position),
          name_(name),
          id_(id) {}

    AllocationNode* FindChildNode(FunctionId id) {
      auto it = children_.find(id);
      return it != children_.end() ? it->second.get() : nullptr;
    }

    AllocationNode* AddChildNode(FunctionId id,
                                 std::unique_ptr<AllocationNode> node) {
      return children_.emplace(id, std::move(node)).first->second.get();
    }

    static FunctionId function_id(int script_id, int start_position,
                                  const char* name) {
      // script_id == kNoScriptId case:
      //   Use function name pointer as an id. Names derived from VM state
      //   must not collide with the builtin names. The least significant bit
      //   of the id is set to 1.
      if (script_id == v8::UnboundScript::kNoScriptId) {
        return reinterpret_cast<intptr_t>(name) | 1;
      }
      // script_id != kNoScriptId case:
      //   Use script_id, start_position pair to uniquelly identify the node.
      //   The least significant bit of the id is set to 0.
      DCHECK(static_cast<unsigned>(start_position) < (1u << 31));
      return (static_cast<uint64_t>(script_id) << 32) + (start_position << 1);
    }

   private:
    // TODO(alph): make use of unordered_map's here. Pay attention to
    // iterator invalidation during TranslateAllocationNode.
    std::map<size_t, unsigned int> allocations_;
    std::map<FunctionId, std::unique_ptr<AllocationNode>> children_;
    AllocationNode* const parent_;
    const int script_id_;
    const int script_position_;
    const char* const name_;
    uint32_t id_;
    bool pinned_ = false;

    friend class SamplingHeapProfiler;

    DISALLOW_COPY_AND_ASSIGN(AllocationNode);
  };

  struct Sample {
    Sample(size_t size_, AllocationNode* owner_, Local<Value> local_,
           SamplingHeapProfiler* profiler_, uint64_t sample_id)
        : size(size_),
          owner(owner_),
          global(reinterpret_cast<v8::Isolate*>(profiler_->isolate_), local_),
          profiler(profiler_),
          sample_id(sample_id) {}
    const size_t size;
    AllocationNode* const owner;
    Global<Value> global;
    SamplingHeapProfiler* const profiler;
    const uint64_t sample_id;

   private:
    DISALLOW_COPY_AND_ASSIGN(Sample);
  };

  SamplingHeapProfiler(Heap* heap, StringsStorage* names, uint64_t rate,
                       int stack_depth, v8::HeapProfiler::SamplingFlags flags);
  ~SamplingHeapProfiler();

  v8::AllocationProfile* GetAllocationProfile();
  StringsStorage* names() const { return names_; }

 private:
  class Observer : public AllocationObserver {
   public:
    Observer(Heap* heap, intptr_t step_size, uint64_t rate,
             SamplingHeapProfiler* profiler,
             base::RandomNumberGenerator* random)
        : AllocationObserver(step_size),
          profiler_(profiler),
          heap_(heap),
          random_(random),
          rate_(rate) {}

   protected:
    void Step(int bytes_allocated, Address soon_object, size_t size) override {
      USE(heap_);
      DCHECK(heap_->gc_state() == Heap::NOT_IN_GC);
      if (soon_object) {
        // TODO(ofrobots): it would be better to sample the next object rather
        // than skipping this sample epoch if soon_object happens to be null.
        profiler_->SampleObject(soon_object, size);
      }
    }

    intptr_t GetNextStepSize() override { return GetNextSampleInterval(rate_); }

   private:
    intptr_t GetNextSampleInterval(uint64_t rate);
    SamplingHeapProfiler* const profiler_;
    Heap* const heap_;
    base::RandomNumberGenerator* const random_;
    uint64_t const rate_;
  };

  void SampleObject(Address soon_object, size_t size);

  const std::vector<v8::AllocationProfile::Sample> BuildSamples() const;

  AllocationNode* FindOrAddChildNode(AllocationNode* parent, const char* name,
                                     int script_id, int start_position);
  static void OnWeakCallback(const WeakCallbackInfo<Sample>& data);

  uint32_t next_node_id() { return ++last_node_id_; }
  uint64_t next_sample_id() { return ++last_sample_id_; }

  // Methods that construct v8::AllocationProfile.

  // Translates the provided AllocationNode *node* returning an equivalent
  // AllocationProfile::Node. The newly created AllocationProfile::Node is added
  // to the provided AllocationProfile *profile*. Line numbers, column numbers,
  // and script names are resolved using *scripts* which maps all currently
  // loaded scripts keyed by their script id.
  v8::AllocationProfile::Node* TranslateAllocationNode(
      AllocationProfile* profile, SamplingHeapProfiler::AllocationNode* node,
      const std::map<int, Handle<Script>>& scripts);
  v8::AllocationProfile::Allocation ScaleSample(size_t size,
                                                unsigned int count) const;
  AllocationNode* AddStack();

  Isolate* const isolate_;
  Heap* const heap_;
  uint64_t last_sample_id_ = 0;
  uint32_t last_node_id_ = 0;
  Observer allocation_observer_;
  StringsStorage* const names_;
  AllocationNode profile_root_;
  std::unordered_map<Sample*, std::unique_ptr<Sample>> samples_;
  const int stack_depth_;
  const uint64_t rate_;
  v8::HeapProfiler::SamplingFlags flags_;

  DISALLOW_COPY_AND_ASSIGN(SamplingHeapProfiler);
};

}  // namespace internal
}  // namespace v8

#endif  // V8_PROFILER_SAMPLING_HEAP_PROFILER_H_
