blob: 32f9d7b089d27904dc5e34f1650360641d3ac7a7 [file] [log] [blame]
/*
* Copyright (c) 2018-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_fast_megapage_table.h"
pas_fast_megapage_table_impl pas_fast_megapage_table_impl_null = {
.index_begin = 0,
.index_end = 0,
.last = NULL,
.bits = { 0 }
};
void pas_fast_megapage_table_initialize_static_by_index(pas_fast_megapage_table* table,
size_t index,
uintptr_t begin,
uintptr_t end,
pas_lock_hold_mode heap_lock_hold_mode)
{
size_t size;
size_t num_fields;
pas_heap_lock_lock_conditionally(heap_lock_hold_mode);
PAS_ASSERT(index < PAS_NUM_STATIC_FAST_MEGAPAGE_TABLES);
PAS_ASSERT(table->instances[index] == &pas_fast_megapage_table_impl_null);
num_fields = end - begin + 1; /* Make end inclusive to allow end to straddle a fast_megapage boundary. */
size = PAS_OFFSETOF(pas_fast_megapage_table_impl, bits) +
sizeof(unsigned) * PAS_BITFIELD_VECTOR_NUM_WORDS(num_fields, PAS_FAST_MEGAPAGE_TABLE_NUM_BITS);
size = pas_round_up_to_power_of_2(size, PAS_MIN_ALIGN);
num_fields = PAS_BITFIELD_VECTOR_NUM_FIELDS(
(size - PAS_OFFSETOF(pas_fast_megapage_table_impl, bits)) /
sizeof(unsigned),
PAS_FAST_MEGAPAGE_TABLE_NUM_BITS);
end = begin + num_fields;
table->instances[index] = pas_immortal_heap_allocate(
size, "pas_fast_megapage_table/instances_array", pas_object_allocation);
pas_zero_memory(table->instances[index], size);
table->instances[index]->index_begin = begin;
table->instances[index]->index_end = end;
pas_heap_lock_unlock_conditionally(heap_lock_hold_mode);
}
void pas_fast_megapage_table_initialize_static(pas_fast_megapage_table* table,
size_t index, uintptr_t begin, uintptr_t end,
pas_lock_hold_mode heap_lock_hold_mode)
{
pas_fast_megapage_table_initialize_static_by_index(table,
index,
begin >> PAS_FAST_MEGAPAGE_SHIFT,
end >> PAS_FAST_MEGAPAGE_SHIFT,
heap_lock_hold_mode);
}
void pas_fast_megapage_table_set_by_index(pas_fast_megapage_table* table,
size_t index, unsigned value,
pas_lock_hold_mode heap_lock_hold_mode)
{
pas_fast_megapage_table_impl* instance;
size_t index_begin;
size_t index_end;
size_t table_index;
pas_heap_lock_lock_conditionally(heap_lock_hold_mode);
if (index < PAS_NUM_FAST_FAST_MEGAPAGE_BITS
&& value == pas_small_segregated_fast_megapage_kind) {
pas_bitvector_set(table->fast_bits, index, true);
return;
}
for (table_index = 0; table_index < PAS_NUM_STATIC_FAST_MEGAPAGE_TABLES; ++table_index) {
instance = table->instances[table_index];
index_begin = instance->index_begin;
index_end = instance->index_end;
if (index < index_begin)
continue;
if (index >= index_end)
continue;
pas_bitfield_vector_set(
instance->bits, PAS_FAST_MEGAPAGE_TABLE_NUM_BITS, index - index_begin, value);
pas_heap_lock_unlock_conditionally(heap_lock_hold_mode);
return;
}
PAS_ASSERT(PAS_USE_DYNAMIC_FAST_MEGAPAGE_TABLE);
instance = table->instances[PAS_DYNAMIC_FAST_MEGAPAGE_TABLE_INDEX];
index_begin = instance->index_begin;
index_end = instance->index_end;
if (PAS_UNLIKELY(index < index_begin || index >= index_end)) {
size_t new_index_begin;
size_t new_index_end;
size_t num_fields;
pas_fast_megapage_table_impl* new_instance;
size_t size;
size_t initialization_index;
if (instance == &pas_fast_megapage_table_impl_null) {
new_index_begin = index;
new_index_end = index + 1;
} else if (index < index_begin) {
PAS_ASSERT(index_begin && index_end);
new_index_begin = PAS_MIN(index,
index_begin - (index_end - index_begin));
new_index_end = index_end;
} else {
PAS_ASSERT(index_begin && index_end);
PAS_ASSERT(index >= index_end);
new_index_begin = index_begin;
new_index_end = PAS_MAX(index + 1,
index_end + (index_end - index_begin));
}
PAS_ASSERT(new_index_end > new_index_begin);
/* make sure we allocate a page. */
num_fields = new_index_end - new_index_begin;
size = PAS_OFFSETOF(pas_fast_megapage_table_impl, bits) +
sizeof(unsigned) * PAS_BITFIELD_VECTOR_NUM_WORDS(num_fields,
PAS_FAST_MEGAPAGE_TABLE_NUM_BITS);
size = pas_round_up_to_power_of_2(size, PAS_INTERNAL_MIN_ALIGN);
num_fields = PAS_BITFIELD_VECTOR_NUM_FIELDS(
(size - PAS_OFFSETOF(pas_fast_megapage_table_impl, bits)) /
sizeof(unsigned),
PAS_FAST_MEGAPAGE_TABLE_NUM_BITS);
new_index_end = new_index_begin + num_fields;
PAS_ASSERT(new_index_end > new_index_begin);
new_instance = pas_immortal_heap_allocate(
size, "pas_fast_megapage_table/instance", pas_object_allocation);
pas_zero_memory(new_instance, size);
new_instance->index_begin = new_index_begin;
new_instance->index_end = new_index_end;
new_instance->last = instance;
for (initialization_index = index_begin;
initialization_index < index_end;
++initialization_index) {
pas_bitfield_vector_set(
new_instance->bits,
PAS_FAST_MEGAPAGE_TABLE_NUM_BITS,
initialization_index - new_index_begin,
pas_bitfield_vector_get(
instance->bits,
PAS_FAST_MEGAPAGE_TABLE_NUM_BITS,
initialization_index - index_begin));
}
pas_fence();
instance = new_instance;
index_begin = new_index_begin;
table->instances[PAS_DYNAMIC_FAST_MEGAPAGE_TABLE_INDEX] = instance;
}
pas_bitfield_vector_set(instance->bits,
PAS_FAST_MEGAPAGE_TABLE_NUM_BITS,
index - index_begin, value);
pas_heap_lock_unlock_conditionally(heap_lock_hold_mode);
}
#endif /* LIBPAS_ENABLED */