// 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 #include #include 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& module, uintptr_t address) const { return module->GetBaseAddress() + module->GetSize() <= address; } bool operator()( uintptr_t address, const std::unique_ptr& 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 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 ModuleCache::GetModules() const { std::vector result; result.reserve(native_modules_.size()); for (const std::unique_ptr& module : native_modules_) result.push_back(module.get()); for (const std::unique_ptr& module : non_native_modules_) result.push_back(module.get()); return result; } void ModuleCache::UpdateNonNativeModules( const std::vector& to_remove, std::vector> to_add) { // Insert the modules to remove into a set to support O(log(n)) lookup below. flat_set 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& 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(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 module) { native_modules_.insert(std::move(module)); } bool ModuleCache::ModuleAndAddressCompare::operator()( const std::unique_ptr& m1, const std::unique_ptr& m2) const { return m1->GetBaseAddress() < m2->GetBaseAddress(); } bool ModuleCache::ModuleAndAddressCompare::operator()( const std::unique_ptr& m1, uintptr_t address) const { return m1->GetBaseAddress() + m1->GetSize() <= address; } bool ModuleCache::ModuleAndAddressCompare::operator()( uintptr_t address, const std::unique_ptr& m2) const { return address < m2->GetBaseAddress(); } } // namespace base