// Copyright 2019 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_HEAP_MEMORY_MEASUREMENT_H_ #define V8_HEAP_MEMORY_MEASUREMENT_H_ #include <list> #include <unordered_map> #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( Isolate* isolate, Handle<NativeContext> context, Handle<JSPromise> 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; 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_; bool reporting_task_pending_ = false; bool delayed_gc_task_pending_ = false; bool eager_gc_task_pending_ = false; base::RandomNumberGenerator random_number_generator_; }; // Infers the native context for some of the heap objects. class V8_EXPORT_PRIVATE NativeContextInferrer { public: // The native_context parameter is both the input and output parameter. // It should be initialized to the context that will be used for the object // if the inference is not successful. The function performs more work if the // context is the shared context. V8_INLINE bool Infer(Isolate* isolate, Map map, HeapObject object, Address* native_context); private: bool InferForContext(Isolate* isolate, Context context, Address* native_context); bool InferForJSFunction(Isolate* isolate, JSFunction function, Address* native_context); bool InferForJSObject(Isolate* isolate, Map map, JSObject object, Address* native_context); }; // Maintains mapping from native contexts to their sizes. class V8_EXPORT_PRIVATE NativeContextStats { public: V8_INLINE void IncrementSize(Address context, Map map, 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); private: V8_INLINE bool HasExternalBytes(Map map); void IncrementExternalSize(Address context, Map map, HeapObject object); std::unordered_map<Address, size_t> size_by_context_; }; } // namespace internal } // namespace v8 #endif // V8_HEAP_MEMORY_MEASUREMENT_H_