blob: 3b55da68ffce912a332b5f19fd049c6eefd15244 [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_GLOBAL_SIZE_DIRECTORY_INLINES_H
#define PAS_SEGREGATED_GLOBAL_SIZE_DIRECTORY_INLINES_H
#include "pas_baseline_allocator_result.h"
#include "pas_baseline_allocator_table.h"
#include "pas_count_lookup_mode.h"
#include "pas_local_allocator.h"
#include "pas_segregated_directory_inlines.h"
#include "pas_segregated_heap.h"
#include "pas_segregated_size_directory.h"
#include "pas_thread_local_cache.h"
PAS_BEGIN_EXTERN_C;
PAS_API pas_baseline_allocator_result
pas_segregated_size_directory_get_allocator_from_tlc(
pas_segregated_size_directory* directory,
size_t count,
pas_count_lookup_mode count_lookup_mode,
pas_heap_config* config,
unsigned* cached_index);
PAS_API pas_baseline_allocator*
pas_segregated_size_directory_select_allocator_slow(
pas_segregated_size_directory* directory);
static PAS_ALWAYS_INLINE pas_baseline_allocator_result
pas_segregated_size_directory_select_allocator(
pas_segregated_size_directory* directory,
size_t count,
pas_count_lookup_mode count_lookup_mode,
pas_heap_config* config,
unsigned* cached_index)
{
if (pas_segregated_size_directory_has_tlc_allocator(directory)
&& (pas_thread_local_cache_try_get() || pas_thread_local_cache_can_set())) {
return pas_segregated_size_directory_get_allocator_from_tlc(
directory, count, count_lookup_mode, config, cached_index);
}
for (;;) {
unsigned index;
pas_baseline_allocator* allocator;
index = directory->baseline_allocator_index;
if (index >= PAS_NUM_BASELINE_ALLOCATORS)
allocator = pas_segregated_size_directory_select_allocator_slow(directory);
else {
allocator = pas_baseline_allocator_table + index;
pas_lock_lock(&allocator->lock);
if (directory->baseline_allocator_index != index) {
pas_lock_unlock(&allocator->lock);
continue;
}
}
PAS_ASSERT(pas_segregated_view_get_size_directory(allocator->u.allocator.view) == directory);
return pas_baseline_allocator_result_create_success(
&allocator->u.allocator, &allocator->lock);
}
}
static PAS_ALWAYS_INLINE size_t
pas_segregated_size_directory_local_allocator_size_for_null_config(void)
{
return PAS_LOCAL_ALLOCATOR_SIZE(0);
}
static PAS_ALWAYS_INLINE size_t pas_segregated_size_directory_local_allocator_size_for_config(
pas_segregated_page_config config)
{
PAS_ASSERT(config.base.is_enabled);
return PAS_LOCAL_ALLOCATOR_SIZE(config.num_alloc_bits);
}
static inline pas_allocator_index
pas_segregated_size_directory_num_allocator_indices_for_allocator_size(size_t size)
{
pas_allocator_index result;
result = (pas_allocator_index)(size / 8);
PAS_TESTING_ASSERT((size_t)result * 8 == size);
return result;
}
static PAS_ALWAYS_INLINE pas_allocator_index
pas_segregated_size_directory_num_allocator_indices_for_config(
pas_segregated_page_config config)
{
static const bool verbose = false;
size_t size;
PAS_ASSERT(config.base.is_enabled);
size = pas_segregated_size_directory_local_allocator_size_for_config(config);
if (verbose) {
pas_log(
"kind = %s, size = %zu.\n",
pas_segregated_page_config_kind_get_string(config.kind),
size);
}
return pas_segregated_size_directory_num_allocator_indices_for_allocator_size(size);
}
static PAS_ALWAYS_INLINE unsigned
pas_segregated_size_directory_take_first_eligible_impl_should_consider_view_parallel(
pas_segregated_directory_bitvector_segment segment,
pas_segregated_directory_iterate_config* config)
{
PAS_UNUSED_PARAM(config);
return segment.eligible_bits;
}
static PAS_ALWAYS_INLINE pas_segregated_view
pas_segregated_size_directory_take_first_eligible_impl(
pas_segregated_directory* directory,
pas_segregated_directory_iterate_config* config,
pas_segregated_view (*create_new_view_callback)(
pas_segregated_directory_iterate_config* config))
{
static const bool verbose = false;
bool did_find_something;
pas_segregated_page_config* page_config_ptr;
pas_segregated_page_config page_config;
pas_segregated_view view;
page_config_ptr = pas_segregated_page_config_kind_get_config(directory->page_config_kind);
page_config = *page_config_ptr;
view = NULL;
if (verbose)
pas_log("%p: At start of take_first_eligible_impl.\n", directory);
for (;;) {
if (verbose)
pas_log("%p: At top of take_first_eligible_impl loop.\n", directory);
config->directory = directory;
config->should_consider_view_parallel =
pas_segregated_size_directory_take_first_eligible_impl_should_consider_view_parallel;
config->consider_view = NULL;
config->arg = NULL;
did_find_something = pas_segregated_directory_iterate_forward_to_take_first_eligible(config);
if (did_find_something) {
view = pas_segregated_directory_get(directory, config->index);
if (verbose) {
pas_log("At index %zu: Taking existing view %p.\n",
(size_t)config->index,
pas_segregated_view_get_ptr(view));
}
PAS_TESTING_ASSERT(config->segment.eligible_bits & config->bit_reference.mask);
if (PAS_SEGREGATED_DIRECTORY_BIT_REFERENCE_SET(
directory, config->bit_reference, eligible, false)) {
if (verbose)
pas_log("Did take first eligible.\n");
break;
}
} else {
size_t new_size;
pas_heap_lock_lock_conditionally(
pas_segregated_page_config_heap_lock_hold_mode(page_config));
new_size = pas_segregated_directory_size(directory);
PAS_ASSERT(new_size >= config->index);
if (new_size == config->index) {
view = create_new_view_callback(config);
pas_segregated_directory_append(directory, config->index, view);
pas_heap_lock_unlock_conditionally(
pas_segregated_page_config_heap_lock_hold_mode(page_config));
break;
}
pas_heap_lock_unlock_conditionally(
pas_segregated_page_config_heap_lock_hold_mode(page_config));
}
}
if (verbose) {
pas_log("Taking eligible view %p (%s).\n",
pas_segregated_view_get_ptr(view),
pas_segregated_view_kind_get_string(pas_segregated_view_get_kind(view)));
}
PAS_TESTING_ASSERT(!PAS_SEGREGATED_DIRECTORY_GET_BIT(
directory, pas_segregated_view_get_index(view), eligible));
return view;
}
PAS_END_EXTERN_C;
#endif /* PAS_SEGREGATED_GLOBAL_SIZE_DIRECTORY_INLINES_H */