blob: 9d28d112b3bdca1f7206509e1465016d402f0d26 [file] [log] [blame]
/*
* Copyright (c) 2019-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_SEGREGATED_SHARED_VIEW_H
#define PAS_SEGREGATED_SHARED_VIEW_H
#include "pas_segregated_page_config.h"
#include "pas_segregated_view.h"
#include "pas_shared_handle_or_page_boundary.h"
#include "pas_utils.h"
PAS_BEGIN_EXTERN_C;
struct pas_extended_segregated_shared_view;
struct pas_segregated_shared_view;
typedef struct pas_extended_segregated_shared_view pas_extended_segregated_shared_view;
typedef struct pas_segregated_shared_view pas_segregated_shared_view;
struct pas_segregated_shared_view {
pas_shared_handle_or_page_boundary shared_handle_or_page_boundary;
pas_lock commit_lock;
pas_lock ownership_lock;
unsigned index : 31;
/* This has roughly the same meaning as in pas_segregated_exclusive_view. */
bool is_owned : 1;
unsigned bump_offset;
unsigned is_in_use_for_allocation_count;
};
static inline pas_segregated_view pas_segregated_shared_view_as_view(pas_segregated_shared_view* view)
{
return pas_segregated_view_create(view, pas_segregated_shared_view_kind);
}
static inline pas_segregated_view pas_segregated_shared_view_as_view_non_null(pas_segregated_shared_view* view)
{
return pas_segregated_view_create_non_null(view, pas_segregated_shared_view_kind);
}
PAS_API pas_segregated_shared_view* pas_segregated_shared_view_create(size_t index);
typedef struct {
unsigned old_bump; /* The start of the allocation. It's _not_ the old value of bump_offset,
since old_bump includes the alignment bump. */
unsigned new_bump; /* What to set bump_offset to. */
unsigned end_bump; /* The end of the allocation (end_bump <= new_bump). */
unsigned num_objects; /* Number of objects in the range. */
} pas_shared_view_computed_bump_result;
static inline pas_shared_view_computed_bump_result
pas_shared_view_computed_bump_result_create_empty(void)
{
pas_shared_view_computed_bump_result result;
result.old_bump = 0;
result.new_bump = 0;
result.end_bump = 0;
result.num_objects = 0;
return result;
}
static PAS_ALWAYS_INLINE pas_shared_view_computed_bump_result
pas_segregated_shared_view_compute_initial_new_bump(
pas_segregated_shared_view* view,
unsigned size,
unsigned alignment,
pas_segregated_page_config page_config)
{
pas_shared_view_computed_bump_result result;
PAS_UNUSED_PARAM(page_config);
/* NOTE: This math cannot overflow because size and alignment are bounded to page size, and
page size is much smaller than 1 << 32. It's not up to this function to assert that bound
since we expect this to be a hot path. Moreover it's the kind of hot path where it's hard
to reduce the amount of work done anywhere else so we might as well not assert too much. */
result.old_bump = view->bump_offset;
result.old_bump = (unsigned)pas_round_up_to_power_of_2(result.old_bump, alignment);
result.new_bump = result.old_bump;
result.new_bump += size;
result.end_bump = result.new_bump;
result.num_objects = 1;
return result;
}
static PAS_ALWAYS_INLINE bool
pas_segregated_shared_view_can_bump(
pas_segregated_shared_view* view,
unsigned size,
unsigned alignment,
pas_segregated_page_config page_config)
{
pas_shared_view_computed_bump_result result;
unsigned bump_limit;
bump_limit = (unsigned)
pas_segregated_page_config_object_payload_end_offset_from_boundary(page_config);
result = pas_segregated_shared_view_compute_initial_new_bump(view, size, alignment, page_config);
return result.new_bump <= bump_limit;
}
static PAS_ALWAYS_INLINE pas_shared_view_computed_bump_result
pas_segregated_shared_view_compute_new_bump(
pas_segregated_shared_view* view,
unsigned size,
unsigned alignment,
pas_segregated_page_config page_config)
{
pas_shared_view_computed_bump_result result;
unsigned total_shift;
unsigned bump_limit;
total_shift = page_config.base.min_align_shift + page_config.sharing_shift;
bump_limit = (unsigned)
pas_segregated_page_config_object_payload_end_offset_from_boundary(page_config);
result = pas_segregated_shared_view_compute_initial_new_bump(view, size, alignment, page_config);
if (result.new_bump > bump_limit)
return pas_shared_view_computed_bump_result_create_empty();
while ((result.new_bump >> total_shift) == (result.old_bump >> total_shift)) {
result.new_bump += size;
if (result.new_bump > bump_limit) {
result.new_bump = bump_limit;
break;
}
result.end_bump = result.new_bump;
result.num_objects++;
}
return result;
}
static PAS_ALWAYS_INLINE pas_shared_view_computed_bump_result
pas_segregated_shared_view_bump(
pas_segregated_shared_view* view,
unsigned size,
unsigned alignment,
pas_segregated_page_config page_config)
{
pas_shared_view_computed_bump_result result;
result = pas_segregated_shared_view_compute_new_bump(
view, size, alignment, page_config);
if (result.num_objects)
view->bump_offset = result.new_bump;
return result;
}
PAS_API pas_heap_summary
pas_segregated_shared_view_compute_summary(pas_segregated_shared_view* view,
pas_segregated_page_config* page_config);
PAS_API bool pas_segregated_shared_view_is_empty(pas_segregated_shared_view* view);
PAS_END_EXTERN_C;
#endif /* PAS_SEGREGATED_SHARED_VIEW_H */