blob: e5b3426022d34a6bc2b3af7dac01d40a28a65f28 [file] [log] [blame]
// 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 BASE_ANDROID_REACHED_ADDRESSES_BITSET_H_
#define BASE_ANDROID_REACHED_ADDRESSES_BITSET_H_
#include <atomic>
#include <vector>
#include "base/base_export.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/no_destructor.h"
namespace base {
namespace android {
// ReachedAddressesBitset is a set that stores addresses for the
// ReachedCodeProfiler in compact form. Its main features are lock-free
// thread-safety and fast adding of elements.
//
// The addresses are kept with |kBytesGranularity| to save the storage space.
//
// Once insterted, elements cannot be erased from the set.
//
// All methods can be called from any thread.
class BASE_EXPORT ReachedAddressesBitset {
public:
// Returns an instance of ReachedAddressesBitset having enough storage space
// to keep all addresses from the .text section.
// Returns nullptr if SUPPORTS_CODE_ORDERING isn't defined.
// This instance is stored in the .bss section of the binary, meaning that it
// doesn't incur the binary size overhead and it doesn't increase the resident
// memory footprint when not used.
static ReachedAddressesBitset* GetTextBitset();
// Inserts |address| into the bitset iff |address| lies in the range between
// |start_address_| and |end_address_|.
void RecordAddress(uintptr_t address);
// Returns a list of recorded addresses in the form of offsets from
// |start_address_|.
std::vector<uint32_t> GetReachedOffsets() const;
private:
friend class ReachedAddressesBitsetTest;
friend class NoDestructor<ReachedAddressesBitset>;
// Represents the number of bytes that are mapped into the same bit in the
// bitset.
static constexpr size_t kBytesGranularity = 4;
// Constructs a ReachedAddressesBitset on top of an external storage of
// |storage_size| pointed by |storage_ptr|. This external storage must outlive
// the constructed bitset instance. The size of storage must be large enough
// to fit all addresses in the range between |start_address| and
// |end_address|.
ReachedAddressesBitset(uintptr_t start_address,
uintptr_t end_address,
std::atomic<uint32_t>* storage_ptr,
size_t storage_size);
size_t NumberOfReachableElements() const;
uintptr_t start_address_;
uintptr_t end_address_;
// This field is not a raw_ptr<> because the rewriter couldn't handle the
// global variable in a build configuration specific code.
RAW_PTR_EXCLUSION std::atomic<uint32_t>* reached_;
};
} // namespace android
} // namespace base
#endif // BASE_ANDROID_REACHED_ADDRESSES_BITSET_H_