119 lines
4.5 KiB
C++
119 lines
4.5 KiB
C++
|
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#include "base/profiler/module_cache.h"
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <iterator>
|
||
|
#include <utility>
|
||
|
|
||
|
namespace base {
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
// Supports heterogeneous comparisons on modules and addresses, for use in
|
||
|
// binary searching modules sorted by range for a contained address.
|
||
|
struct ModuleAddressCompare {
|
||
|
bool operator()(const std::unique_ptr<const ModuleCache::Module>& module,
|
||
|
uintptr_t address) const {
|
||
|
return module->GetBaseAddress() + module->GetSize() <= address;
|
||
|
}
|
||
|
|
||
|
bool operator()(
|
||
|
uintptr_t address,
|
||
|
const std::unique_ptr<const ModuleCache::Module>& module) const {
|
||
|
return address < module->GetBaseAddress();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
ModuleCache::ModuleCache() = default;
|
||
|
ModuleCache::~ModuleCache() = default;
|
||
|
|
||
|
const ModuleCache::Module* ModuleCache::GetModuleForAddress(uintptr_t address) {
|
||
|
const auto non_native_module_loc = non_native_modules_.find(address);
|
||
|
if (non_native_module_loc != non_native_modules_.end())
|
||
|
return non_native_module_loc->get();
|
||
|
|
||
|
const auto native_module_loc = native_modules_.find(address);
|
||
|
if (native_module_loc != native_modules_.end())
|
||
|
return native_module_loc->get();
|
||
|
|
||
|
std::unique_ptr<const Module> new_module = CreateModuleForAddress(address);
|
||
|
if (!new_module)
|
||
|
return nullptr;
|
||
|
const auto loc = native_modules_.insert(std::move(new_module));
|
||
|
return loc.first->get();
|
||
|
}
|
||
|
|
||
|
std::vector<const ModuleCache::Module*> ModuleCache::GetModules() const {
|
||
|
std::vector<const Module*> result;
|
||
|
result.reserve(native_modules_.size());
|
||
|
for (const std::unique_ptr<const Module>& module : native_modules_)
|
||
|
result.push_back(module.get());
|
||
|
for (const std::unique_ptr<const Module>& module : non_native_modules_)
|
||
|
result.push_back(module.get());
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void ModuleCache::UpdateNonNativeModules(
|
||
|
const std::vector<const Module*>& to_remove,
|
||
|
std::vector<std::unique_ptr<const Module>> to_add) {
|
||
|
// Insert the modules to remove into a set to support O(log(n)) lookup below.
|
||
|
flat_set<const Module*> to_remove_set(to_remove.begin(), to_remove.end());
|
||
|
|
||
|
// Reorder the modules to be removed to the last slots in the set, then move
|
||
|
// them to the inactive modules, then erase the moved-from modules from the
|
||
|
// set. The flat_set docs endorse using base::EraseIf() which performs the
|
||
|
// same operations -- exclusive of the moves -- so this is OK even though it
|
||
|
// might seem like we're messing with the internal set representation.
|
||
|
//
|
||
|
// remove_if is O(m*log(r)) where m is the number of current modules and r is
|
||
|
// the number of modules to remove. insert and erase are both O(r).
|
||
|
auto first_module_to_remove = std::remove_if(
|
||
|
non_native_modules_.begin(), non_native_modules_.end(),
|
||
|
[&to_remove_set](const std::unique_ptr<const Module>& module) {
|
||
|
return to_remove_set.find(module.get()) != to_remove_set.end();
|
||
|
});
|
||
|
// All modules requested to be removed should have been found.
|
||
|
DCHECK_EQ(static_cast<ptrdiff_t>(to_remove.size()),
|
||
|
std::distance(first_module_to_remove, non_native_modules_.end()));
|
||
|
inactive_non_native_modules_.insert(
|
||
|
inactive_non_native_modules_.end(),
|
||
|
std::make_move_iterator(first_module_to_remove),
|
||
|
std::make_move_iterator(non_native_modules_.end()));
|
||
|
non_native_modules_.erase(first_module_to_remove, non_native_modules_.end());
|
||
|
|
||
|
// Insert the modules to be added. This operation is O((m + a) + a*log(a))
|
||
|
// where m is the number of current modules and a is the number of modules to
|
||
|
// be added.
|
||
|
non_native_modules_.insert(std::make_move_iterator(to_add.begin()),
|
||
|
std::make_move_iterator(to_add.end()));
|
||
|
}
|
||
|
|
||
|
void ModuleCache::AddCustomNativeModule(std::unique_ptr<const Module> module) {
|
||
|
native_modules_.insert(std::move(module));
|
||
|
}
|
||
|
|
||
|
bool ModuleCache::ModuleAndAddressCompare::operator()(
|
||
|
const std::unique_ptr<const Module>& m1,
|
||
|
const std::unique_ptr<const Module>& m2) const {
|
||
|
return m1->GetBaseAddress() < m2->GetBaseAddress();
|
||
|
}
|
||
|
|
||
|
bool ModuleCache::ModuleAndAddressCompare::operator()(
|
||
|
const std::unique_ptr<const Module>& m1,
|
||
|
uintptr_t address) const {
|
||
|
return m1->GetBaseAddress() + m1->GetSize() <= address;
|
||
|
}
|
||
|
|
||
|
bool ModuleCache::ModuleAndAddressCompare::operator()(
|
||
|
uintptr_t address,
|
||
|
const std::unique_ptr<const Module>& m2) const {
|
||
|
return address < m2->GetBaseAddress();
|
||
|
}
|
||
|
|
||
|
} // namespace base
|