#ifndef V8_HEAP_MEMORY_MEASUREMENT_H_
#define V8_HEAP_MEMORY_MEASUREMENT_H_
#include <list>
#include <unordered_map>
#include "include/v8-statistics.h"
#include "src/base/platform/elapsed-timer.h"
#include "src/base/utils/random-number-generator.h"
#include "src/common/globals.h"
#include "src/objects/contexts.h"
#include "src/objects/map.h"
#include "src/objects/objects.h"
namespace v8 {
namespace internal {
class Heap;
class NativeContextStats;
class MemoryMeasurement {
public:
explicit MemoryMeasurement(Isolate* isolate);
bool EnqueueRequest(std::unique_ptr<v8::MeasureMemoryDelegate> delegate,
v8::MeasureMemoryExecution execution,
const std::vector<Handle<NativeContext>> contexts);
std::vector<Address> StartProcessing();
void FinishProcessing(const NativeContextStats& stats);
static std::unique_ptr<v8::MeasureMemoryDelegate> DefaultDelegate(
v8::Isolate* isolate, v8::Local<v8::Context> context,
v8::Local<v8::Promise::Resolver> promise, v8::MeasureMemoryMode mode);
private:
static const int kGCTaskDelayInSeconds = 10;
struct Request {
std::unique_ptr<v8::MeasureMemoryDelegate> delegate;
Handle<WeakFixedArray> contexts;
std::vector<size_t> sizes;
size_t shared;
size_t wasm_code;
size_t wasm_metadata;
base::ElapsedTimer timer;
};
void ScheduleReportingTask();
void ReportResults();
void ScheduleGCTask(v8::MeasureMemoryExecution execution);
bool IsGCTaskPending(v8::MeasureMemoryExecution execution);
void SetGCTaskPending(v8::MeasureMemoryExecution execution);
void SetGCTaskDone(v8::MeasureMemoryExecution execution);
int NextGCTaskDelayInSeconds();
std::list<Request> received_;
std::list<Request> processing_;
std::list<Request> done_;
Isolate* isolate_;
std::shared_ptr<v8::TaskRunner> task_runner_;
bool reporting_task_pending_ = false;
bool delayed_gc_task_pending_ = false;
bool eager_gc_task_pending_ = false;
base::RandomNumberGenerator random_number_generator_;
};
class V8_EXPORT_PRIVATE NativeContextInferrer {
public:
V8_INLINE bool Infer(PtrComprCageBase cage_base, Tagged<Map> map,
Tagged<HeapObject> object, Address* native_context);
};
class V8_EXPORT_PRIVATE NativeContextStats {
public:
V8_INLINE void IncrementSize(Address context, Tagged<Map> map,
Tagged<HeapObject> object, size_t size);
size_t Get(Address context) const {
const auto it = size_by_context_.find(context);
if (it == size_by_context_.end()) return 0;
return it->second;
}
void Clear();
void Merge(const NativeContextStats& other);
bool Empty() const { return size_by_context_.empty(); }
private:
V8_INLINE bool HasExternalBytes(Tagged<Map> map);
void IncrementExternalSize(Address context, Tagged<Map> map,
Tagged<HeapObject> object);
std::unordered_map<Address, size_t> size_by_context_;
};
}
}
#endif