| /* |
| * 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_heap.h" |
| |
| #include "pas_all_heaps.h" |
| #include "pas_heap_config.h" |
| #include "pas_heap_inlines.h" |
| #include "pas_heap_ref.h" |
| #include "pas_heap_table.h" |
| #include "pas_immortal_heap.h" |
| #include "pas_log.h" |
| #include "pas_monotonic_time.h" |
| #include "pas_primitive_heap_ref.h" |
| #include "pas_segregated_size_directory.h" |
| |
| pas_heap* pas_heap_create(pas_heap_ref* heap_ref, |
| pas_heap_ref_kind heap_ref_kind, |
| pas_heap_config* config, |
| pas_heap_runtime_config* runtime_config) |
| { |
| static const bool verbose = false; |
| pas_heap* heap; |
| |
| if (verbose) { |
| pas_log("Creating heap for size = %lu, alignment = %lu.\n", |
| config->get_type_size(heap_ref->type), |
| config->get_type_alignment(heap_ref->type)); |
| } |
| |
| PAS_ASSERT(config->get_type_size(heap_ref->type) >= 1); |
| PAS_ASSERT(pas_is_power_of_2(config->get_type_alignment(heap_ref->type))); |
| PAS_ASSERT(pas_is_aligned(config->get_type_size(heap_ref->type), |
| config->get_type_alignment(heap_ref->type))); |
| |
| heap = pas_immortal_heap_allocate(sizeof(pas_heap), "pas_heap", pas_object_allocation); |
| pas_zero_memory(heap, sizeof(pas_heap)); |
| heap->type = heap_ref->type; |
| pas_segregated_heap_construct( |
| &heap->segregated_heap, heap, config, runtime_config); |
| pas_large_heap_construct(&heap->large_heap); |
| heap->heap_ref = heap_ref; |
| heap->heap_ref_kind = heap_ref_kind; |
| heap->config_kind = config->kind; |
| |
| pas_all_heaps_add_heap(heap); |
| |
| return heap; |
| } |
| |
| size_t pas_heap_get_type_size(pas_heap* heap) |
| { |
| if (!heap) |
| return 1; |
| return pas_heap_config_kind_get_config(heap->config_kind)->get_type_size(heap->type); |
| } |
| |
| size_t pas_heap_get_num_free_bytes(pas_heap* heap) |
| { |
| return |
| pas_segregated_heap_get_num_free_bytes(&heap->segregated_heap) |
| + pas_large_heap_get_num_free_bytes(&heap->large_heap); |
| } |
| |
| typedef struct { |
| pas_heap* heap; |
| pas_heap_for_each_live_object_callback callback; |
| void* arg; |
| } for_each_live_object_data; |
| |
| static bool for_each_live_object_small_object_callback(pas_segregated_heap* heap, |
| uintptr_t begin, |
| size_t size, |
| void* arg) |
| { |
| for_each_live_object_data* data; |
| |
| data = arg; |
| |
| PAS_ASSERT(&data->heap->segregated_heap == heap); |
| |
| return data->callback(data->heap, begin, size, data->arg); |
| } |
| |
| static bool for_each_live_object_large_object_callback(pas_large_heap* heap, |
| uintptr_t begin, |
| uintptr_t end, |
| void* arg) |
| { |
| for_each_live_object_data* data; |
| |
| data = arg; |
| |
| PAS_ASSERT(&data->heap->large_heap == heap); |
| |
| return data->callback(data->heap, begin, end - begin, data->arg); |
| } |
| |
| bool pas_heap_for_each_live_object(pas_heap* heap, |
| pas_heap_for_each_live_object_callback callback, |
| void* arg, |
| pas_lock_hold_mode heap_lock_hold_mode) |
| { |
| for_each_live_object_data data; |
| bool result; |
| |
| data.heap = heap; |
| data.callback = callback; |
| data.arg = arg; |
| |
| pas_heap_lock_lock_conditionally(heap_lock_hold_mode); |
| |
| result = |
| pas_segregated_heap_for_each_live_object(&heap->segregated_heap, |
| for_each_live_object_small_object_callback, |
| &data) && |
| pas_large_heap_for_each_live_object(&heap->large_heap, |
| for_each_live_object_large_object_callback, |
| &data); |
| |
| pas_heap_lock_unlock_conditionally(heap_lock_hold_mode); |
| |
| return result; |
| } |
| |
| pas_heap_summary pas_heap_compute_summary(pas_heap* heap, |
| pas_lock_hold_mode heap_lock_hold_mode) |
| { |
| pas_heap_summary result; |
| pas_heap_lock_lock_conditionally(heap_lock_hold_mode); |
| result = pas_heap_summary_add( |
| pas_segregated_heap_compute_summary(&heap->segregated_heap), |
| pas_large_heap_compute_summary(&heap->large_heap)); |
| pas_heap_lock_unlock_conditionally(heap_lock_hold_mode); |
| return result; |
| } |
| |
| void pas_heap_reset_heap_ref(pas_heap* heap) |
| { |
| if (!heap->heap_ref) |
| return; |
| |
| heap->heap_ref->heap = NULL; |
| heap->heap_ref->allocator_index = UINT_MAX; |
| switch (heap->heap_ref_kind) { |
| case pas_normal_heap_ref_kind: |
| return; |
| case pas_primitive_heap_ref_kind: |
| ((pas_primitive_heap_ref*)heap->heap_ref)->cached_index = UINT_MAX; |
| return; |
| case pas_fake_heap_ref_kind: |
| PAS_ASSERT(!"Should not be reached"); |
| return; |
| } |
| |
| PAS_ASSERT(!"Should not be reached"); |
| } |
| |
| pas_segregated_size_directory* |
| pas_heap_ensure_size_directory_for_count_slow( |
| pas_heap* heap, |
| size_t count, |
| size_t alignment, |
| pas_count_lookup_mode force_count_lookup, |
| pas_heap_config* config, |
| unsigned* cached_index) |
| { |
| pas_segregated_size_directory* result; |
| |
| pas_heap_lock_lock(); |
| result = pas_segregated_heap_ensure_size_directory_for_count( |
| &heap->segregated_heap, count, alignment, force_count_lookup, config, cached_index, |
| pas_segregated_size_directory_full_creation_mode); |
| pas_heap_lock_unlock(); |
| |
| return result; |
| } |
| |
| #endif /* LIBPAS_ENABLED */ |