blob: c5a22b1d52acd01a7c8c110a7897b8fda4e36fc3 [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.
*/
#include "pas_config.h"
#if LIBPAS_ENABLED
#include "pas_bitfit_view.h"
#include "pas_bitfit_directory.h"
#include "pas_bitfit_page.h"
#include "pas_bitfit_view_inlines.h"
#include "pas_epoch.h"
#include "pas_page_sharing_pool.h"
pas_bitfit_view* pas_bitfit_view_create(pas_bitfit_directory* directory,
unsigned index)
{
static const bool verbose = false;
pas_bitfit_view* result;
result = pas_immortal_heap_allocate(
sizeof(pas_bitfit_view),
"pas_bitfit_view",
pas_object_allocation);
if (verbose) {
pas_log("Creating view %p with config %s\n",
result, pas_bitfit_page_config_kind_get_string(directory->config_kind));
}
result->page_boundary = NULL;
pas_compact_bitfit_directory_ptr_store(&result->directory, directory);
result->is_owned = false;
result->index = index;
pas_lock_construct(&result->ownership_lock);
pas_lock_construct(&result->commit_lock);
return result;
}
void pas_bitfit_view_note_nonemptiness(pas_bitfit_view* view)
{
pas_bitfit_directory_max_free_did_become_unprocessed_unchecked(
pas_compact_bitfit_directory_ptr_load_non_null(&view->directory),
view->index,
"become unprocessed on note_nonemptiness");
}
static void did_become_empty_for_bits(pas_bitfit_view* view, pas_bitfit_page* page)
{
page->use_epoch = pas_get_epoch();
pas_bitfit_directory_view_did_become_empty(
pas_compact_bitfit_directory_ptr_load_non_null(&view->directory), view);
}
void pas_bitfit_view_note_full_emptiness(pas_bitfit_view* view, pas_bitfit_page* page)
{
did_become_empty_for_bits(view, page);
pas_bitfit_directory_max_free_did_become_empty(
pas_compact_bitfit_directory_ptr_load_non_null(&view->directory),
view->index,
"become empty on note_emptiness");
}
void pas_bitfit_view_note_partial_emptiness(pas_bitfit_view* view, pas_bitfit_page* page)
{
did_become_empty_for_bits(view, page);
}
void pas_bitfit_view_note_max_free(pas_bitfit_view* view)
{
pas_bitfit_directory_max_free_did_become_unprocessed(
pas_compact_bitfit_directory_ptr_load_non_null(&view->directory),
view->index,
"become unprocessed on note_max_free");
}
static pas_heap_summary compute_summary(pas_bitfit_view* view)
{
static const bool verbose = false;
pas_bitfit_page_config* config_ptr;
pas_bitfit_page_config config;
void* boundary;
pas_bitfit_page* page;
pas_heap_summary result;
size_t begin;
size_t end;
size_t offset;
config_ptr = pas_bitfit_page_config_kind_get_config(
pas_compact_bitfit_directory_ptr_load_non_null(
&view->directory)->config_kind);
config = *config_ptr;
result = pas_heap_summary_create_empty();
if (!view->is_owned) {
size_t payload_size;
payload_size = pas_bitfit_page_payload_size(config);
result.decommitted += config.base.page_size;
result.free += payload_size;
result.free_decommitted += payload_size;
return result;
}
if (verbose) {
pas_log("Getting page boundary for view %p and config %s\n",
view, pas_bitfit_page_config_kind_get_string(config.kind));
}
boundary = view->page_boundary;
page = pas_bitfit_page_for_boundary(boundary, config);
pas_page_base_compute_committed_when_owned(&page->base, &result);
begin = pas_bitfit_page_offset_to_first_object(config);
end = pas_bitfit_page_offset_to_end_of_last_object(config);
pas_page_base_add_free_range(
&page->base, &result, pas_range_create(0, begin), pas_free_meta_range);
pas_page_base_add_free_range(
&page->base, &result, pas_range_create(end, config.base.page_size),
pas_free_meta_range);
for (offset = begin; offset < end; offset += pas_page_base_config_min_align(config.base)) {
if (pas_bitvector_get(pas_bitfit_page_free_bits(page),
offset >> config.base.min_align_shift)) {
pas_page_base_add_free_range(
&page->base, &result,
pas_range_create(offset, offset + pas_page_base_config_min_align(config.base)),
pas_free_object_range);
} else
result.allocated += pas_page_base_config_min_align(config.base);
}
return result;
}
pas_heap_summary pas_bitfit_view_compute_summary(pas_bitfit_view* view)
{
pas_heap_summary result;
pas_lock_lock(&view->ownership_lock);
result = compute_summary(view);
pas_lock_unlock(&view->ownership_lock);
return result;
}
typedef struct {
pas_bitfit_view* view;
pas_bitfit_view_for_each_live_object_callback callback;
void* arg;
} for_each_live_object_data;
static bool for_each_live_object_callback(uintptr_t begin,
size_t size,
void* arg)
{
for_each_live_object_data* data;
data = arg;
return data->callback(data->view, begin, size, data->arg);
}
static bool for_each_live_object(
pas_bitfit_view* view,
pas_bitfit_view_for_each_live_object_callback callback,
void* arg)
{
pas_bitfit_page_config* config_ptr;
pas_bitfit_page_config config;
void* boundary;
pas_bitfit_page* page;
for_each_live_object_data data;
if (!view->is_owned)
return true;
config_ptr = pas_bitfit_page_config_kind_get_config(
pas_compact_bitfit_directory_ptr_load_non_null(&view->directory)->config_kind);
config = *config_ptr;
boundary = view->page_boundary;
page = pas_bitfit_page_for_boundary(boundary, config);
data.view = view;
data.callback = callback;
data.arg = arg;
return pas_bitfit_page_for_each_live_object(page, for_each_live_object_callback, &data);
}
bool pas_bitfit_view_for_each_live_object(
pas_bitfit_view* view,
pas_bitfit_view_for_each_live_object_callback callback,
void* arg)
{
bool result;
pas_lock_lock(&view->ownership_lock);
result = for_each_live_object(view, callback, arg);
pas_lock_unlock(&view->ownership_lock);
return result;
}
#endif /* LIBPAS_ENABLED */