| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_RENDERER_V8_UNWINDER_H_ |
| #define CHROME_RENDERER_V8_UNWINDER_H_ |
| |
| #include <memory> |
| #include <set> |
| |
| #include "base/check_op.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/profiler/unwinder.h" |
| #include "v8/include/v8-unwinder.h" |
| |
| namespace v8 { |
| class Isolate; |
| } // namespace v8 |
| |
| // Implements stack frame unwinding for V8 generated code frames, for use with |
| // the StackSamplingProfiler. |
| class V8Unwinder : public base::Unwinder { |
| public: |
| explicit V8Unwinder(v8::Isolate* isolate); |
| ~V8Unwinder() override; |
| |
| V8Unwinder(const V8Unwinder&) = delete; |
| V8Unwinder& operator=(const V8Unwinder&) = delete; |
| |
| // Unwinder: |
| void InitializeModules() override; |
| std::unique_ptr<base::UnwinderStateCapture> CreateUnwinderStateCapture() |
| override; |
| void OnStackCapture(base::UnwinderStateCapture* capture_state) override; |
| void UpdateModules(base::UnwinderStateCapture* capture_state) override; |
| bool CanUnwindFrom(const base::Frame& current_frame) const override; |
| base::UnwindResult TryUnwind(base::UnwinderStateCapture* capture_state, |
| base::RegisterContext* thread_context, |
| uintptr_t stack_top, |
| std::vector<base::Frame>* stack) override; |
| |
| // Build ids generated by the unwinder. Exposed for test use. |
| static const char kV8EmbeddedCodeRangeBuildId[]; |
| static const char kV8CodeRangeBuildId[]; |
| |
| protected: |
| // Invokes CopyCodePages on the Isolate. Virtual to provide a seam for testing |
| // of module processing behavior. |
| virtual size_t CopyCodePages(size_t capacity, v8::MemoryRange* code_pages); |
| |
| private: |
| // Custom container for storing V8 code memory ranges. We use this type rather |
| // than std::vector to guarantee that no heap allocation occurs during the |
| // operations used in OnStackCapture(). |
| class MemoryRanges : public base::UnwinderStateCapture { |
| public: |
| explicit MemoryRanges(size_t size); |
| ~MemoryRanges() override; |
| |
| // Functions that must not heap allocate: |
| // Returns a pointer to the start of the internal buffer. |
| v8::MemoryRange* buffer() { return ranges_.get(); } |
| const v8::MemoryRange* buffer() const { return ranges_.get(); } |
| size_t size() const { return size_; } |
| |
| // Shrinks the size if `size_` is larger than `size`. |
| void ShrinkSize(size_t size); |
| |
| private: |
| size_t size_; |
| std::unique_ptr<v8::MemoryRange[]> ranges_; |
| }; |
| |
| // Compares modules by their extents in memory. |
| struct ModuleCompare { |
| bool operator()(const base::ModuleCache::Module* a, |
| const base::ModuleCache::Module* b) const; |
| }; |
| |
| const raw_ptr<v8::Isolate> isolate_; |
| const v8::JSEntryStubs js_entry_stubs_; |
| const v8::MemoryRange embedded_code_range_; |
| |
| // The number of code ranges required to represent all of ranges supplied by |
| // V8 on the last call to CopyCodePages(). |
| size_t required_code_ranges_capacity_ = 0; |
| |
| // Records the currently active V8 modules, ordered by their extents in |
| // memory. |
| std::set<raw_ptr<const base::ModuleCache::Module, SetExperimental>, |
| ModuleCompare> |
| modules_; |
| }; |
| |
| #endif // CHROME_RENDERER_V8_UNWINDER_H_ |