blob: 93f32976a0649ba7b7c958b98a5d928eba5ef276 [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.
*/
#include "pas_config.h"
#if LIBPAS_ENABLED
#include "pas_bitfit_size_class.h"
#include "pas_bitfit_directory.h"
#include "pas_heap_lock.h"
#include "pas_immortal_heap.h"
pas_compact_atomic_bitfit_size_class_ptr*
pas_bitfit_size_class_find_insertion_point(pas_bitfit_directory* directory,
unsigned size)
{
pas_compact_atomic_bitfit_size_class_ptr* next_ptr;
next_ptr = &directory->largest_size_class;
for (;;) {
pas_bitfit_size_class* current_size_class;
current_size_class = pas_compact_atomic_bitfit_size_class_ptr_load(next_ptr);
if (!current_size_class || size >= current_size_class->size)
return next_ptr;
next_ptr = &current_size_class->next_smaller;
}
}
void pas_bitfit_size_class_construct(pas_bitfit_size_class* size_class,
unsigned size,
pas_bitfit_directory* directory,
pas_compact_atomic_bitfit_size_class_ptr* insertion_point)
{
pas_bitfit_size_class* next_size_class;
pas_heap_lock_assert_held();
PAS_ASSERT(insertion_point);
pas_versioned_field_construct(&size_class->first_free, 0);
size_class->size = size;
pas_compact_bitfit_directory_ptr_store(&size_class->directory, directory);
pas_compact_atomic_bitfit_size_class_ptr_store(&size_class->next_smaller, NULL);
next_size_class = pas_compact_atomic_bitfit_size_class_ptr_load(insertion_point);
PAS_ASSERT(!next_size_class || size > next_size_class->size);
pas_compact_atomic_bitfit_size_class_ptr_store(
&size_class->next_smaller, next_size_class);
pas_compact_atomic_bitfit_size_class_ptr_store(insertion_point, size_class);
}
pas_bitfit_size_class* pas_bitfit_size_class_create(
unsigned size,
pas_bitfit_directory* directory,
pas_compact_atomic_bitfit_size_class_ptr* insertion_point)
{
pas_bitfit_size_class* result;
result = pas_immortal_heap_allocate_with_alignment(
sizeof(pas_bitfit_size_class),
alignof(pas_bitfit_size_class),
"pas_bitfit_size_class",
pas_object_allocation);
pas_bitfit_size_class_construct(result, size, directory, insertion_point);
return result;
}
pas_bitfit_view*
pas_bitfit_size_class_get_first_free_view(pas_bitfit_size_class* size_class,
pas_bitfit_page_config* page_config)
{
pas_bitfit_directory* directory;
pas_versioned_field first_free_for_size;
pas_versioned_field first_unprocessed_free;
pas_bitfit_view_and_index view_and_index;
uintptr_t start_index;
directory = pas_compact_bitfit_directory_ptr_load_non_null(&size_class->directory);
first_free_for_size = pas_versioned_field_read_to_watch(&size_class->first_free);
first_unprocessed_free = pas_versioned_field_read_to_watch(&directory->first_unprocessed_free);
start_index = PAS_MIN(first_free_for_size.value,
first_unprocessed_free.value);
PAS_ASSERT((unsigned)start_index == start_index);
view_and_index = pas_bitfit_directory_get_first_free_view(
directory, (unsigned)start_index, size_class->size, page_config);
PAS_ASSERT(view_and_index.view);
/* So, this is the first view that had enough stuff for our requested size. That means it also
has to be the first unprocessed or the first unprocessed has a higher index - since otherwise
we would have picked the lower index here. */
pas_versioned_field_maximize_watched(
&size_class->first_free, first_free_for_size, view_and_index.index);
pas_versioned_field_maximize_watched(
&directory->first_unprocessed_free, first_unprocessed_free, view_and_index.index);
return view_and_index.view;
}
#endif /* LIBPAS_ENABLED */