Example #1
0
static Heap_Resize_status _Heap_Resize_block_checked(
  Heap_Control *heap,
  Heap_Block *block,
  uintptr_t alloc_begin,
  uintptr_t new_alloc_size,
  uintptr_t *old_size,
  uintptr_t *new_size
)
{
  Heap_Statistics *const stats = &heap->stats;

  uintptr_t const block_begin = (uintptr_t) block;
  uintptr_t block_size = _Heap_Block_size( block );
  uintptr_t block_end = block_begin + block_size;

  uintptr_t alloc_size = block_end - alloc_begin + HEAP_ALLOC_BONUS;

  Heap_Block *next_block = _Heap_Block_at( block, block_size );
  uintptr_t next_block_size = _Heap_Block_size( next_block );
  bool next_block_is_free = _Heap_Is_free( next_block );

  _HAssert( _Heap_Is_block_in_heap( heap, next_block ) );
  _HAssert( _Heap_Is_prev_used( next_block ) );

  *old_size = alloc_size;

  if ( next_block_is_free ) {
    block_size += next_block_size;
    alloc_size += next_block_size;
  }

  if ( new_alloc_size > alloc_size ) {
    return HEAP_RESIZE_UNSATISFIED;
  }

  if ( next_block_is_free ) {
    _Heap_Block_set_size( block, block_size );

    _Heap_Free_list_remove( next_block );

    next_block = _Heap_Block_at( block, block_size );
    next_block->size_and_flag |= HEAP_PREV_BLOCK_USED;

    /* Statistics */
    --stats->free_blocks;
    stats->free_size -= next_block_size;
  }

  block = _Heap_Block_allocate( heap, block, alloc_begin, new_alloc_size );

  block_size = _Heap_Block_size( block );
  next_block = _Heap_Block_at( block, block_size );
  *new_size = (uintptr_t) next_block - alloc_begin + HEAP_ALLOC_BONUS;

  /* Statistics */
  ++stats->resizes;

  return HEAP_RESIZE_SUCCESSFUL;
}
Example #2
0
static void _Heap_Link_above(
  Heap_Block *link,
  Heap_Block *first_block,
  Heap_Block *last_block
)
{
  uintptr_t const link_begin = (uintptr_t) link;
  uintptr_t const first_block_begin = (uintptr_t) first_block;

  _Heap_Block_set_size( link, first_block_begin - link_begin );

  last_block->size_and_flag |= HEAP_PREV_BLOCK_USED;
}
Example #3
0
static void _Heap_Merge_above(
  Heap_Control *heap,
  Heap_Block *last_block,
  uintptr_t extend_area_end
)
{
  uintptr_t const page_size = heap->page_size;
  uintptr_t const last_block_begin = (uintptr_t) last_block;
  uintptr_t const last_block_new_size = _Heap_Align_down(
    extend_area_end - last_block_begin - HEAP_BLOCK_HEADER_SIZE,
    page_size
  );
  Heap_Block *const new_last_block =
    _Heap_Block_at( last_block, last_block_new_size );

  new_last_block->size_and_flag =
    (last_block->size_and_flag - last_block_new_size)
      | HEAP_PREV_BLOCK_USED;

  _Heap_Block_set_size( last_block, last_block_new_size );

  _Heap_Free_block( heap, last_block );
}
Example #4
0
Heap_Extend_status _Heap_Extend(
  Heap_Control *heap,
  void *area_begin_ptr,
  uintptr_t area_size,
  uintptr_t *amount_extended
)
{
  Heap_Statistics *const stats = &heap->stats;
  uintptr_t const area_begin = (uintptr_t) area_begin_ptr;
  uintptr_t const heap_area_begin = heap->area_begin;
  uintptr_t const heap_area_end = heap->area_end;
  uintptr_t const new_heap_area_end = heap_area_end + area_size;
  uintptr_t extend_size = 0;
  Heap_Block *const last_block = heap->last_block;

  /*
   *  There are five possibilities for the location of starting
   *  address:
   *
   *    1. non-contiguous lower address     (NOT SUPPORTED)
   *    2. contiguous lower address         (NOT SUPPORTED)
   *    3. in the heap                      (ERROR)
   *    4. contiguous higher address        (SUPPORTED)
   *    5. non-contiguous higher address    (NOT SUPPORTED)
   *
   *  As noted, this code only supports (4).
   */

  if ( area_begin >= heap_area_begin && area_begin < heap_area_end ) {
    return HEAP_EXTEND_ERROR; /* case 3 */
  } else if ( area_begin != heap_area_end ) {
    return HEAP_EXTEND_NOT_IMPLEMENTED; /* cases 1, 2, and 5 */
  }

  /*
   *  Currently only case 4 should make it to this point.
   *  The basic trick is to make the extend area look like a used
   *  block and free it.
   */

  heap->area_end = new_heap_area_end;

  extend_size = new_heap_area_end
    - (uintptr_t) last_block - HEAP_BLOCK_HEADER_SIZE;
  extend_size = _Heap_Align_down( extend_size, heap->page_size );

  *amount_extended = extend_size;

  if( extend_size >= heap->min_block_size ) {
    Heap_Block *const new_last_block = _Heap_Block_at( last_block, extend_size );

    _Heap_Block_set_size( last_block, extend_size );

    new_last_block->size_and_flag =
      ((uintptr_t) heap->first_block - (uintptr_t) new_last_block)
        | HEAP_PREV_BLOCK_USED;

    heap->last_block = new_last_block;

    /* Statistics */
    stats->size += extend_size;
    ++stats->used_blocks;
    --stats->frees; /* Do not count subsequent call as actual free() */

    _Heap_Free( heap, (void *) _Heap_Alloc_area_of_block( last_block ));
  }

  return HEAP_EXTEND_SUCCESSFUL;
}
void _Heap_Block_split(
  Heap_Control *heap,
  Heap_Block *block,
  Heap_Block *free_list_anchor,
  uintptr_t alloc_size
)
{
  Heap_Statistics *const stats = &heap->stats;

  uintptr_t const page_size = heap->page_size;
  uintptr_t const min_block_size = heap->min_block_size;
  uintptr_t const min_alloc_size = min_block_size - HEAP_BLOCK_HEADER_SIZE;

  uintptr_t const block_size = _Heap_Block_size( block );

  uintptr_t const used_size =
    _Heap_Max( alloc_size, min_alloc_size ) + HEAP_BLOCK_HEADER_SIZE;
  uintptr_t const used_block_size = _Heap_Align_up( used_size, page_size );

  uintptr_t const free_size = block_size + HEAP_BLOCK_SIZE_OFFSET - used_size;
  uintptr_t const free_size_limit = min_block_size + HEAP_BLOCK_SIZE_OFFSET;

  Heap_Block *next_block = _Heap_Block_at( block, block_size );

  _HAssert( used_size <= block_size + HEAP_BLOCK_SIZE_OFFSET );
  _HAssert( used_size + free_size == block_size + HEAP_BLOCK_SIZE_OFFSET );

  if ( free_size >= free_size_limit ) {
    Heap_Block *const free_block = _Heap_Block_at( block, used_block_size );
    uintptr_t free_block_size = block_size - used_block_size;

    _HAssert( used_block_size + free_block_size == block_size );

    _Heap_Block_set_size( block, used_block_size );

    /* Statistics */
    stats->free_size += free_block_size;

    if ( _Heap_Is_used( next_block ) ) {
      _Heap_Free_list_insert_after( free_list_anchor, free_block );

      /* Statistics */
      ++stats->free_blocks;
    } else {
      uintptr_t const next_block_size = _Heap_Block_size( next_block );

      _Heap_Free_list_replace( next_block, free_block );

      free_block_size += next_block_size;

      next_block = _Heap_Block_at( free_block, free_block_size );
    }

    free_block->size_and_flag = free_block_size | HEAP_PREV_BLOCK_USED;

    next_block->prev_size = free_block_size;
    next_block->size_and_flag &= ~HEAP_PREV_BLOCK_USED;
  } else {
    next_block->size_and_flag |= HEAP_PREV_BLOCK_USED;
  }
}