blob: 404ca03e7e47e3caa1f1deb8f9dbf1d70bc44a69 [file] [log] [blame]
/*
* Copyright (c) 2020-2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PAS_BITFIT_DIRECTORY_H
#define PAS_BITFIT_DIRECTORY_H
#include "pas_bitfit_max_free.h"
#include "pas_bitfit_page_config_kind.h"
#include "pas_bitfit_view_and_index.h"
#include "pas_compact_atomic_bitfit_size_class_ptr.h"
#include "pas_compact_atomic_bitfit_view_ptr.h"
#include "pas_heap_summary.h"
#include "pas_page_sharing_participant.h"
#include "pas_segmented_vector.h"
#include "pas_versioned_field.h"
PAS_BEGIN_EXTERN_C;
struct pas_bitfit_directory;
struct pas_bitfit_directory_bitvector_segment;
struct pas_bitfit_size_class;
struct pas_bitfit_page;
struct pas_bitfit_view;
struct pas_segregated_heap;
typedef struct pas_bitfit_directory pas_bitfit_directory;
typedef struct pas_bitfit_directory_bitvector_segment pas_bitfit_directory_bitvector_segment;
typedef struct pas_bitfit_size_class pas_bitfit_size_class;
typedef struct pas_bitfit_page pas_bitfit_page;
typedef struct pas_bitfit_view pas_bitfit_view;
typedef struct pas_segregated_heap pas_segregated_heap;
#define PAS_BITFIT_DIRECTORY_VERBOSE_MAX_FREE false
PAS_DECLARE_SEGMENTED_VECTOR(pas_bitfit_directory_max_free_vector,
pas_bitfit_max_free,
128);
PAS_DECLARE_SEGMENTED_VECTOR(pas_bitfit_directory_view_vector,
pas_compact_atomic_bitfit_view_ptr,
8);
struct pas_bitfit_directory_bitvector_segment {
unsigned empty_bits;
};
#define PAS_BITFIT_DIRECTORY_BITVECTOR_SEGMENT_INITIALIZER \
((pas_bitfit_directory_bitvector_segment){ \
.empty_bits = 0, \
})
PAS_DECLARE_SEGMENTED_VECTOR(pas_bitfit_directory_segmented_bitvectors,
pas_bitfit_directory_bitvector_segment,
4);
struct PAS_ALIGNED(sizeof(pas_versioned_field)) pas_bitfit_directory {
pas_versioned_field first_unprocessed_free;
pas_versioned_field first_empty;
pas_versioned_field last_empty_plus_one; /* Zero means there aren't any. */
pas_segregated_heap* heap;
pas_bitfit_directory_segmented_bitvectors bitvectors;
pas_bitfit_directory_max_free_vector max_frees;
pas_bitfit_directory_view_vector views;
pas_page_sharing_participant_payload physical_sharing_payload;
pas_compact_atomic_bitfit_size_class_ptr largest_size_class;
pas_bitfit_page_config_kind config_kind : 8;
};
PAS_API void pas_bitfit_directory_construct(pas_bitfit_directory* directory,
pas_bitfit_page_config* config,
pas_segregated_heap* heap);
static inline unsigned pas_bitfit_directory_size(pas_bitfit_directory* directory)
{
return directory->views.size;
}
static inline pas_bitfit_max_free* pas_bitfit_directory_get_max_free_ptr(
pas_bitfit_directory* directory,
size_t index)
{
return pas_bitfit_directory_max_free_vector_get_ptr_checked(&directory->max_frees, index);
}
static inline pas_bitfit_max_free pas_bitfit_directory_get_max_free(pas_bitfit_directory* directory,
size_t index)
{
return *pas_bitfit_directory_get_max_free_ptr(directory, index);
}
static inline void pas_bitfit_directory_set_max_free_unchecked(
pas_bitfit_directory* directory,
size_t index,
pas_bitfit_max_free max_free,
const char* reason)
{
if (PAS_BITFIT_DIRECTORY_VERBOSE_MAX_FREE)
pas_log("%p:%zu: setting max_free unchecked to %u (%s)\n", directory, index, max_free, reason);
*pas_bitfit_directory_get_max_free_ptr(directory, index) = max_free;
}
/* We maintain the convention that you should only do this while holding the ownership lock. */
static inline void pas_bitfit_directory_set_max_free_not_empty_impl(pas_bitfit_directory* directory,
size_t index,
pas_bitfit_max_free max_free)
{
pas_bitfit_max_free* ptr;
ptr = pas_bitfit_directory_get_max_free_ptr(directory, index);
if (*ptr == PAS_BITFIT_MAX_FREE_EMPTY) {
pas_log("%p:%zu: found empty when setting max_free\n", directory, index);
PAS_ASSERT(*ptr != PAS_BITFIT_MAX_FREE_EMPTY);
}
PAS_ASSERT(max_free != PAS_BITFIT_MAX_FREE_EMPTY);
*ptr = max_free;
}
static inline void pas_bitfit_directory_set_processed_max_free(pas_bitfit_directory* directory,
size_t index,
pas_bitfit_max_free max_free,
const char* reason)
{
if (PAS_BITFIT_DIRECTORY_VERBOSE_MAX_FREE)
pas_log("%p:%zu: setting max_free to processed %u (%s)\n", directory, index, max_free, reason);
PAS_ASSERT(max_free < (size_t)PAS_BITFIT_MAX_FREE_UNPROCESSED);
PAS_ASSERT(PAS_BITFIT_MAX_FREE_UNPROCESSED < PAS_BITFIT_MAX_FREE_EMPTY);
pas_bitfit_directory_set_max_free_not_empty_impl(directory, index, max_free);
}
static inline void pas_bitfit_directory_set_unprocessed_max_free_unchecked(
pas_bitfit_directory* directory,
size_t index,
const char* reason)
{
if (PAS_BITFIT_DIRECTORY_VERBOSE_MAX_FREE)
pas_log("%p:%zu: setting max_free to unprocessed unchecked (%s)\n", directory, index, reason);
*pas_bitfit_directory_get_max_free_ptr(directory, index) = PAS_BITFIT_MAX_FREE_UNPROCESSED;
}
static inline void pas_bitfit_directory_set_empty_max_free(
pas_bitfit_directory* directory,
size_t index,
const char* reason)
{
if (PAS_BITFIT_DIRECTORY_VERBOSE_MAX_FREE)
pas_log("%p:%zu: setting max_free to empty (%s)\n", directory, index, reason);
*pas_bitfit_directory_get_max_free_ptr(directory, index) = PAS_BITFIT_MAX_FREE_EMPTY;
}
static inline void pas_bitfit_directory_set_unprocessed_max_free(pas_bitfit_directory* directory,
size_t index,
const char* reason)
{
if (PAS_BITFIT_DIRECTORY_VERBOSE_MAX_FREE)
pas_log("%p:%zu: setting max_free to unprocessed (%s)\n", directory, index, reason);
pas_bitfit_directory_set_max_free_not_empty_impl(directory, index, PAS_BITFIT_MAX_FREE_UNPROCESSED);
}
PAS_API void pas_bitfit_directory_update_biasing_eligibility(pas_bitfit_directory* directory,
size_t index);
PAS_API void pas_bitfit_directory_max_free_did_become_unprocessed(pas_bitfit_directory* directory,
size_t index,
const char* reason);
PAS_API void pas_bitfit_directory_max_free_did_become_unprocessed_unchecked(
pas_bitfit_directory* directory,
size_t index,
const char* reason);
PAS_API void pas_bitfit_directory_max_free_did_become_empty_without_biasing_update(
pas_bitfit_directory* directory,
size_t index,
const char* reason);
PAS_API void pas_bitfit_directory_max_free_did_become_empty(pas_bitfit_directory* directory,
size_t index,
const char* reason);
static inline pas_compact_atomic_bitfit_view_ptr*
pas_bitfit_directory_get_view_ptr(pas_bitfit_directory* directory,
size_t index)
{
return pas_bitfit_directory_view_vector_get_ptr_checked(&directory->views, index);
}
static inline pas_bitfit_view* pas_bitfit_directory_get_view(pas_bitfit_directory* directory,
size_t index)
{
return pas_compact_atomic_bitfit_view_ptr_load(
pas_bitfit_directory_get_view_ptr(directory, index));
}
/* This does not update any indices held onto by the directory or size classes. To do that, use
size_class's version of this function. */
PAS_API pas_bitfit_view_and_index
pas_bitfit_directory_get_first_free_view(pas_bitfit_directory* directory,
unsigned start_index,
unsigned size,
pas_bitfit_page_config* page_config);
PAS_API pas_heap_summary pas_bitfit_directory_compute_summary(pas_bitfit_directory* directory);
typedef bool (*pas_bitfit_directory_for_each_live_object_callback)(
pas_bitfit_directory* directory,
pas_bitfit_view* view,
uintptr_t begin,
size_t size,
void* arg);
PAS_API bool pas_bitfit_directory_for_each_live_object(
pas_bitfit_directory* directory,
pas_bitfit_directory_for_each_live_object_callback callback,
void* arg);
PAS_API bool pas_bitfit_directory_does_sharing(pas_bitfit_directory* directory);
PAS_API uint64_t pas_bitfit_directory_get_use_epoch(pas_bitfit_directory* directory);
PAS_API bool pas_bitfit_directory_get_empty_bit_at_index(
pas_bitfit_directory* directory,
size_t index);
/* Returns whether we changed the value. */
PAS_API bool pas_bitfit_directory_set_empty_bit_at_index(
pas_bitfit_directory* directory,
size_t index,
bool value);
PAS_API void pas_bitfit_directory_view_did_become_empty_at_index(
pas_bitfit_directory* directory,
size_t index);
PAS_API void pas_bitfit_directory_view_did_become_empty(
pas_bitfit_directory* directory,
pas_bitfit_view* view);
PAS_API pas_page_sharing_pool_take_result pas_bitfit_directory_take_last_empty(
pas_bitfit_directory* directory,
pas_deferred_decommit_log* decommit_log,
pas_lock_hold_mode heap_lock_hold_mode);
PAS_API void pas_bitfit_directory_dump_reference(
pas_bitfit_directory* directory, pas_stream* stream);
PAS_API void pas_bitfit_directory_dump_for_spectrum(pas_stream* stream, void* directory);
PAS_END_EXTERN_C;
#endif /* PAS_BITFIT_DIRECTORY_H */