blob: 343c30f3e38df1cc79df4ce3717039052f738b99 [file] [log] [blame]
/*
* Copyright (c) 2020 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_PAGE_BASE_CONFIG_H
#define PAS_PAGE_BASE_CONFIG_H
#include "pas_lock.h"
#include "pas_page_granule_use_count.h"
#include "pas_page_kind.h"
#include "pas_utils.h"
PAS_BEGIN_EXTERN_C;
struct pas_bitfit_page_config;
struct pas_enumerator;
struct pas_heap_config;
struct pas_page_base;
struct pas_page_base_config;
struct pas_physical_memory_transaction;
struct pas_segregated_heap;
struct pas_segregated_page_config;
typedef struct pas_bitfit_page_config pas_bitfit_page_config;
typedef struct pas_enumerator pas_enumerator;
typedef struct pas_heap_config pas_heap_config;
typedef struct pas_page_base pas_page_base;
typedef struct pas_page_base_config pas_page_base_config;
typedef struct pas_physical_memory_transaction pas_physical_memory_transaction;
typedef struct pas_segregated_heap pas_segregated_heap;
typedef struct pas_segregated_page_config pas_segregated_page_config;
typedef pas_page_base* (*pas_page_base_config_page_header_for_boundary)(void* boundary);
typedef void* (*pas_page_base_config_boundary_for_page_header)(pas_page_base* page);
typedef pas_page_base* (*pas_page_base_config_page_header_for_boundary_remote)(
pas_enumerator* enumerator, void* boundary);
typedef void* (*pas_page_base_config_page_allocator)(
pas_segregated_heap*, pas_physical_memory_transaction* transaction);
typedef pas_page_base* (*pas_page_base_config_create_page_header)(
void* boundary, pas_lock_hold_mode heap_lock_hold_mode);
typedef void (*pas_page_base_config_destroy_page_header)(
pas_page_base* page_base, pas_lock_hold_mode heap_lock_hold_mode);
struct pas_page_base_config {
/* Are we using this page config? */
bool is_enabled;
/* This points to the owning heap config. Currently there is always an owning heap config. */
pas_heap_config* heap_config_ptr;
/* This always self-points. It's useful for going from a page_config to a page_config_ptr. */
pas_page_base_config* page_config_ptr;
/* What page_kind to put in pages allocated by this config. This happens to tell if the config
is a segregated or a bitfit config. */
pas_page_kind page_kind;
/* Smallest small object size and the minimum alignment. */
uint8_t min_align_shift;
/* Page size. This is the amount of bytes that we allocate to create one. */
size_t page_size;
/* The commit granule size. */
size_t granule_size;
/* The header size. This can be computed if you know the kind of page config we're dealing
with. But we don't always, so it's best to store it. */
size_t page_header_size;
/* Hard cut-off for object sizes for this variant. For segregated page configs, it's recommended
that this is something that divides cleanly into page_object_payload_size. For bitfit page
configs, this must be strictly smaller than PAS_BITFIT_MAX_FREE_UNPROCESSED * min_align. */
size_t max_object_size;
/* How do we go from the page boundary to the page header and back again? */
pas_page_base_config_page_header_for_boundary page_header_for_boundary;
pas_page_base_config_boundary_for_page_header boundary_for_page_header;
/* Need to also be able to get the page header remotely during enumeration. */
pas_page_base_config_page_header_for_boundary_remote page_header_for_boundary_remote;
/* What's the first byte at which the object payload could start relative to the boundary? */
uintptr_t page_object_payload_offset;
/* How many bytes are provisioned for objects past that offset? */
size_t page_object_payload_size;
/* This is the allocator used to create pages. */
pas_page_base_config_page_allocator page_allocator;
/* Some configurations need to be able to allocate/free the page header. The allocation would
happen after page allocation or commit, and the deallocation would happen right before or
right after page decommit. */
pas_page_base_config_create_page_header create_page_header;
pas_page_base_config_destroy_page_header destroy_page_header;
};
static PAS_ALWAYS_INLINE size_t pas_page_base_config_min_align(pas_page_base_config config)
{
return (size_t)1 << (size_t)config.min_align_shift;
}
static PAS_ALWAYS_INLINE uintptr_t
pas_page_base_config_object_payload_end_offset_from_boundary(pas_page_base_config config)
{
return config.page_object_payload_offset + config.page_object_payload_size;
}
#define PAS_PAGE_BASE_CONFIG_NUM_GRANULE_BYTES(num_granules) \
((num_granules) == 1 ? 0 : (num_granules) * sizeof(pas_page_granule_use_count))
static PAS_ALWAYS_INLINE size_t
pas_page_base_config_num_granule_bytes(pas_page_base_config config)
{
return PAS_PAGE_BASE_CONFIG_NUM_GRANULE_BYTES(config.page_size / config.granule_size);
}
static PAS_ALWAYS_INLINE pas_page_config_kind
pas_page_base_config_get_config_kind(pas_page_base_config config)
{
return pas_page_kind_get_config_kind(config.page_kind);
}
static PAS_ALWAYS_INLINE bool pas_page_base_config_is_segregated(pas_page_base_config config)
{
return pas_page_base_config_get_config_kind(config) == pas_page_config_kind_segregated;
}
static PAS_ALWAYS_INLINE bool pas_page_base_config_is_bitfit(pas_page_base_config config)
{
return pas_page_base_config_get_config_kind(config) == pas_page_config_kind_segregated;
}
static inline pas_segregated_page_config*
pas_page_base_config_get_segregated(pas_page_base_config* config)
{
PAS_ASSERT(pas_page_base_config_is_segregated(*config));
return (pas_segregated_page_config*)config;
}
static inline pas_bitfit_page_config*
pas_page_base_config_get_bitfit(pas_page_base_config* config)
{
PAS_ASSERT(pas_page_base_config_is_bitfit(*config));
return (pas_bitfit_page_config*)config;
}
PAS_END_EXTERN_C;
#endif /* PAS_PAGE_BASE_CONFIG_H */