diff --git a/src/liballocator/mem-heap.c b/src/liballocator/mem-heap.c index 025a811c3..b57ada43c 100644 --- a/src/liballocator/mem-heap.c +++ b/src/liballocator/mem-heap.c @@ -415,7 +415,7 @@ mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to all mem_check_heap (); - if (alloc_term == MEM_HEAP_ALLOC_SHORT_TERM) + if (alloc_term == MEM_HEAP_ALLOC_LONG_TERM) { block_p = mem_heap.first_block_p; direction = MEM_DIRECTION_NEXT; @@ -473,7 +473,7 @@ mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to all mem_init_block_header (new_free_block_first_chunk_p, 0, MEM_BLOCK_FREE, - block_p /* there we will place new allocated block */, + block_p, next_block_p); mem_block_header_t *new_free_block_p = (mem_block_header_t*) new_free_block_first_chunk_p; @@ -521,6 +521,143 @@ mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to all return data_space_p; } /* mem_heap_alloc_block */ +/** + * Try to resize memory region. + * + * @return true - if resize is successful, + * false - if there is not enough memory in front of the block. + */ +bool +mem_heap_try_resize_block (uint8_t *ptr, /**< pointer to beginning of data space of the block to resize */ + size_t size_in_bytes) /**< new block size */ +{ + /* checking that ptr points to the heap */ + JERRY_ASSERT(ptr >= mem_heap.heap_start + && ptr <= mem_heap.heap_start + mem_heap.heap_size); + + mem_check_heap (); + + mem_block_header_t *block_p = (mem_block_header_t*) ptr - 1; + + VALGRIND_DEFINED_STRUCT(block_p); + + JERRY_ASSERT(block_p->magic_num == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK); + + /* For heap statistics unit we show what is going on as though + * the block is freed and then new block (the same or resized) + * is allocated */ + mem_heap_stat_free_block (block_p); + + size_t current_block_may_expand_up_to = mem_get_block_data_space_size (block_p); + + bool is_resized = false; + + if (current_block_may_expand_up_to >= size_in_bytes) + { + is_resized = true; + } + else + { + size_t need_additional_bytes = size_in_bytes - current_block_may_expand_up_to; + + mem_block_header_t *next_block_p = mem_get_next_block_by_direction (block_p, MEM_DIRECTION_NEXT); + + if (next_block_p != NULL) + { + VALGRIND_DEFINED_STRUCT (next_block_p); + + if (next_block_p->magic_num == MEM_MAGIC_NUM_OF_FREE_BLOCK) + { + size_t next_block_data_space_size = mem_get_block_data_space_size (next_block_p); + + if (next_block_data_space_size >= need_additional_bytes) + { + /* next block is free and contains enough space */ + + is_resized = true; + + size_t new_block_chunks_count = mem_get_block_chunks_count_from_data_size (size_in_bytes); + size_t current_block_chunks_count = mem_get_block_chunks_count (block_p); + size_t next_block_chunks_count = mem_get_block_chunks_count (next_block_p); + + JERRY_ASSERT (new_block_chunks_count <= current_block_chunks_count + next_block_chunks_count); + + size_t diff_in_chunks = (size_t) ((current_block_chunks_count + + next_block_chunks_count) - new_block_chunks_count); + + mem_block_header_t *block_after_next_p = mem_get_next_block_by_direction (next_block_p, + MEM_DIRECTION_NEXT); + mem_block_header_t *new_next_of_current_block_p; + mem_block_header_t *new_prev_of_block_after_next_p; + + if (diff_in_chunks > 0) + { + mem_block_header_t *new_free_block_p = (mem_block_header_t*) ((uint8_t*) block_p + + new_block_chunks_count * MEM_HEAP_CHUNK_SIZE); + + mem_init_block_header ((uint8_t*) new_free_block_p, + 0, + MEM_BLOCK_FREE, + block_p, + block_after_next_p); + + new_prev_of_block_after_next_p = new_free_block_p; + new_next_of_current_block_p = new_free_block_p; + } + else + { + new_prev_of_block_after_next_p = block_p; + new_next_of_current_block_p = block_after_next_p; + } + + block_p->neighbours[ MEM_DIRECTION_NEXT ] = mem_get_block_neighbour_field (block_p, + new_next_of_current_block_p); + if (block_after_next_p != NULL) + { + VALGRIND_DEFINED_STRUCT (block_after_next_p); + + mem_heap_offset_t offset = mem_get_block_neighbour_field (new_prev_of_block_after_next_p, + block_after_next_p); + block_after_next_p->neighbours[ MEM_DIRECTION_PREV ] = offset; + + VALGRIND_NOACCESS_STRUCT (block_after_next_p); + } + else + { + mem_heap.last_block_p = new_prev_of_block_after_next_p; + } + } + } + else + { + JERRY_ASSERT (next_block_p->magic_num == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK); + } + + VALGRIND_NOACCESS_STRUCT (next_block_p); + } + } + + if (is_resized) + { + JERRY_ASSERT ((mem_heap_offset_t) size_in_bytes == size_in_bytes); + + if (size_in_bytes >= block_p->allocated_bytes) + { + VALGRIND_UNDEFINED_SPACE (ptr + block_p->allocated_bytes, size_in_bytes - block_p->allocated_bytes); + } + + block_p->allocated_bytes = (mem_heap_offset_t) size_in_bytes; + } + + mem_heap_stat_alloc_block (block_p); + + VALGRIND_NOACCESS_STRUCT(block_p); + + mem_check_heap (); + + return is_resized; +} /* mem_heap_try_resize_block */ + /** * Free the memory block. */ diff --git a/src/liballocator/mem-heap.h b/src/liballocator/mem-heap.h index cc6125de9..c6361a7ab 100644 --- a/src/liballocator/mem-heap.h +++ b/src/liballocator/mem-heap.h @@ -42,6 +42,7 @@ typedef enum extern void mem_heap_init (uint8_t *heap_start, size_t heap_size); extern void mem_heap_finalize (void); extern uint8_t* mem_heap_alloc_block (size_t size_in_bytes, mem_heap_alloc_term_t alloc_term); +extern bool mem_heap_try_resize_block (uint8_t *ptr, size_t size_in_bytes); extern void mem_heap_free_block (uint8_t *ptr); extern size_t mem_heap_recommend_allocation_size (size_t minimum_allocation_size); extern void mem_heap_print (bool dump_block_headers, bool dump_block_data, bool dump_stats); diff --git a/tests/unit/test_heap.c b/tests/unit/test_heap.c index 884e6fbf3..9fce50614 100644 --- a/tests/unit/test_heap.c +++ b/tests/unit/test_heap.c @@ -22,17 +22,17 @@ extern long int time (long int *__timer); extern int printf (__const char *__restrict __format, ...); extern void *memset (void *__s, int __c, size_t __n); -// Heap size is 8K -const size_t test_heap_size = 8 * 1024; +// Heap size is 32K +const size_t test_heap_size = 32 * 1024; // Iterations count -const uint32_t test_iters = 1024 * 1024; +const uint32_t test_iters = 64 * 1024; // Subiterations count -const uint32_t test_sub_iters = 3; +const uint32_t test_sub_iters = 32; // Threshold size of block to allocate -const uint32_t test_threshold_block_size = 2048; +const uint32_t test_threshold_block_size = 8192; int main( int __unused argc, @@ -69,6 +69,25 @@ main( int __unused argc, // mem_heap_print( true); + for ( uint32_t j = 0; j < subiters; j++ ) + { + if ( ptrs[j] != NULL && (rand () % 2) == 0 ) + { + for( size_t k = 0; k < sizes[j]; k++ ) + { + JERRY_ASSERT( ptrs[j][k] == 0 ); + } + + size_t new_size = (unsigned int) rand() % ( test_threshold_block_size ); + + if (mem_heap_try_resize_block (ptrs[j], new_size)) + { + sizes[j] = new_size; + memset (ptrs[j], 0, sizes[j]); + } + } + } + for ( uint32_t j = 0; j < subiters; j++ ) { if ( ptrs[j] != NULL )