diff --git a/jerry-core/mem/mem-allocator.cpp b/jerry-core/mem/mem-allocator.cpp index 1a79c9a858..dc5c7a0f40 100644 --- a/jerry-core/mem/mem-allocator.cpp +++ b/jerry-core/mem/mem-allocator.cpp @@ -30,7 +30,8 @@ /** * Area for heap */ -static uint8_t mem_heap_area[ MEM_HEAP_AREA_SIZE ] __attribute__ ((aligned (MEM_ALIGNMENT))); +static uint8_t mem_heap_area[ MEM_HEAP_AREA_SIZE ] __attribute__ ((aligned (JERRY_MAX (MEM_ALIGNMENT, + MEM_HEAP_CHUNK_SIZE)))); /** * The 'try to give memory back' callback diff --git a/jerry-core/mem/mem-heap.cpp b/jerry-core/mem/mem-heap.cpp index 18980699af..8c8223b6c4 100644 --- a/jerry-core/mem/mem-heap.cpp +++ b/jerry-core/mem/mem-heap.cpp @@ -396,6 +396,9 @@ mem_is_block_free (const mem_block_header_t *block_header_p) /**< block header * /** * Startup initialization of heap + * + * Note: + * heap start and size should be aligned on MEM_HEAP_CHUNK_SIZE */ void mem_heap_init (uint8_t *heap_start, /**< first address of heap space */ @@ -403,8 +406,12 @@ mem_heap_init (uint8_t *heap_start, /**< first address of heap space */ { JERRY_ASSERT (heap_start != NULL); JERRY_ASSERT (heap_size != 0); - JERRY_ASSERT (heap_size % MEM_HEAP_CHUNK_SIZE == 0); + + JERRY_STATIC_ASSERT ((MEM_HEAP_CHUNK_SIZE & (MEM_HEAP_CHUNK_SIZE - 1u)) == 0); JERRY_ASSERT ((uintptr_t) heap_start % MEM_ALIGNMENT == 0); + JERRY_ASSERT ((uintptr_t) heap_start % MEM_HEAP_CHUNK_SIZE == 0); + JERRY_ASSERT (heap_size % MEM_HEAP_CHUNK_SIZE == 0); + JERRY_ASSERT (heap_size <= (1u << MEM_HEAP_OFFSET_LOG)); mem_heap.heap_start = heap_start; @@ -800,6 +807,7 @@ mem_heap_free_block (void *ptr) /**< pointer to beginning of data space of the b /* marking the block free */ block_p->allocated_bytes = 0; + block_p->length_type = mem_block_length_type_t::GENERAL; if (next_block_p != NULL) { @@ -866,12 +874,12 @@ mem_heap_free_block (void *ptr) /**< pointer to beginning of data space of the b } /* mem_heap_free_block */ /** - * Find beginning of user data in a block from pointer, + * Find beginning of user data in a one-chunked block from pointer, * pointing into it, i.e. into [block_data_space_start; block_data_space_end) range. * * Note: - * Pointer must point to the memory region which was previously allocated - * with mem_heap_alloc_block and is currently valid. + * Pointer must point to the one-chunked memory region which was previously allocated + * with mem_heap_alloc_chunked_block and is currently valid. * * Note: * The interface should only be used for determining where the user space of heap-allocated block begins. @@ -880,49 +888,59 @@ mem_heap_free_block (void *ptr) /**< pointer to beginning of data space of the b * @return beginning of user data space of block identified by the pointer */ void* -mem_heap_get_block_start (void *ptr) /**< pointer into a block */ +mem_heap_get_chunked_block_start (void *ptr) /**< pointer into a block */ { - mem_check_heap (); - - /* - * PERF: consider introducing bitmap of block beginnings - */ + JERRY_STATIC_ASSERT ((MEM_HEAP_CHUNK_SIZE & (MEM_HEAP_CHUNK_SIZE - 1u)) == 0); + JERRY_ASSERT (((uintptr_t) mem_heap.heap_start % MEM_HEAP_CHUNK_SIZE) == 0); JERRY_ASSERT (mem_heap.heap_start <= ptr && ptr < mem_heap.heap_start + mem_heap.heap_size); - const mem_block_header_t *block_p = mem_heap.first_block_p; + uintptr_t uintptr = (uintptr_t) ptr; + uintptr_t uintptr_chunk_aligned = JERRY_ALIGNDOWN (uintptr, MEM_HEAP_CHUNK_SIZE); + + JERRY_ASSERT (uintptr > uintptr_chunk_aligned); + + mem_block_header_t *block_p = (mem_block_header_t *) uintptr_chunk_aligned; + JERRY_ASSERT (block_p->length_type == mem_block_length_type_t::ONE_CHUNKED); + +#ifndef JERRY_NDEBUG + const mem_block_header_t *block_iter_p = mem_heap.first_block_p; + bool is_found = false; /* searching for corresponding block */ - while (block_p != NULL) + while (block_iter_p != NULL) { - VALGRIND_DEFINED_STRUCT (block_p); + VALGRIND_DEFINED_STRUCT (block_iter_p); - const mem_block_header_t *next_block_p = mem_get_next_block_by_direction (block_p, + const mem_block_header_t *next_block_p = mem_get_next_block_by_direction (block_iter_p, MEM_DIRECTION_NEXT); - bool is_found = (ptr > block_p - && (ptr < next_block_p - || next_block_p == NULL)); + is_found = (ptr > block_iter_p + && (ptr < next_block_p + || next_block_p == NULL)); if (is_found) { - JERRY_ASSERT (!mem_is_block_free (block_p)); - JERRY_ASSERT (block_p + 1 <= ptr); - JERRY_ASSERT (ptr < ((uint8_t*) (block_p + 1) + block_p->allocated_bytes)); + JERRY_ASSERT (!mem_is_block_free (block_iter_p)); + JERRY_ASSERT (block_iter_p + 1 <= ptr); + JERRY_ASSERT (ptr < ((uint8_t*) (block_iter_p + 1) + block_iter_p->allocated_bytes)); } - VALGRIND_NOACCESS_STRUCT (block_p); + VALGRIND_NOACCESS_STRUCT (block_iter_p); if (is_found) { - return (void*) (block_p + 1); + break; } - block_p = next_block_p; + block_iter_p = next_block_p; } - JERRY_UNREACHABLE (); -} /* mem_heap_get_block_start */ + JERRY_ASSERT (is_found && block_p == block_iter_p); +#endif /* !JERRY_NDEBUG */ + + return (void*) (block_p + 1); +} /* mem_heap_get_chunked_block_start */ /** * Get size of one-chunked block data space diff --git a/jerry-core/mem/mem-heap.h b/jerry-core/mem/mem-heap.h index e701105b4a..baa9575bbc 100644 --- a/jerry-core/mem/mem-heap.h +++ b/jerry-core/mem/mem-heap.h @@ -44,7 +44,7 @@ extern void mem_heap_finalize (void); extern void* mem_heap_alloc_block (size_t size_in_bytes, mem_heap_alloc_term_t alloc_term); extern void* mem_heap_alloc_chunked_block (mem_heap_alloc_term_t alloc_term); extern void mem_heap_free_block (void *ptr); -extern void* mem_heap_get_block_start (void *ptr); +extern void* mem_heap_get_chunked_block_start (void *ptr); extern size_t mem_heap_get_chunked_block_data_size (void); extern size_t __attr_pure___ 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.cpp b/tests/unit/test_heap.cpp index 6e2a3d9449..46830fecaf 100644 --- a/tests/unit/test_heap.cpp +++ b/tests/unit/test_heap.cpp @@ -39,6 +39,7 @@ extern "C" uint8_t *ptrs[test_sub_iters]; size_t sizes[test_sub_iters]; +bool is_one_chunked[test_sub_iters]; static void test_heap_give_some_memory_back (mem_try_give_memory_back_severity_t severity) @@ -82,12 +83,13 @@ test_heap_give_some_memory_back (mem_try_give_memory_back_severity_t severity) } } /* test_heap_give_some_memory_back */ +uint8_t test_native_heap[test_heap_size] __attribute__ ((aligned (JERRY_MAX (MEM_ALIGNMENT, + MEM_HEAP_CHUNK_SIZE)))); + int main (int __attr_unused___ argc, char __attr_unused___ **argv) { - uint8_t test_native_heap[test_heap_size]; - mem_heap_init (test_native_heap, sizeof (test_native_heap)); srand ((unsigned int) time (NULL)); @@ -103,17 +105,31 @@ main (int __attr_unused___ argc, { for (uint32_t j = 0; j < test_sub_iters; j++) { - size_t size = (size_t) rand () % test_threshold_block_size; - ptrs[j] = (uint8_t*) mem_heap_alloc_block (size, - (rand () % 2) ? - MEM_HEAP_ALLOC_LONG_TERM : MEM_HEAP_ALLOC_SHORT_TERM); - sizes[j] = size; + if (rand () % 2) + { + size_t size = (size_t) rand () % test_threshold_block_size; + ptrs[j] = (uint8_t*) mem_heap_alloc_block (size, + (rand () % 2) ? + MEM_HEAP_ALLOC_LONG_TERM : MEM_HEAP_ALLOC_SHORT_TERM); + sizes[j] = size; + is_one_chunked[j] = false; + } + else + { + ptrs[j] = (uint8_t*) mem_heap_alloc_chunked_block ((rand () % 2) ? + MEM_HEAP_ALLOC_LONG_TERM : MEM_HEAP_ALLOC_SHORT_TERM); + sizes[j] = mem_heap_get_chunked_block_data_size (); + is_one_chunked[j] = true; + } - JERRY_ASSERT (size == 0 || ptrs[j] != NULL); + JERRY_ASSERT (sizes[j] == 0 || ptrs[j] != NULL); memset (ptrs[j], 0, sizes[j]); - JERRY_ASSERT (ptrs[j] == NULL - || mem_heap_get_block_start (ptrs[j] + (size_t) rand () % sizes[j]) == ptrs[j]); + if (is_one_chunked[j]) + { + JERRY_ASSERT (ptrs[j] != NULL + && mem_heap_get_chunked_block_start (ptrs[j] + (size_t) rand () % sizes[j]) == ptrs[j]); + } } // mem_heap_print (true); @@ -127,8 +143,11 @@ main (int __attr_unused___ argc, JERRY_ASSERT (ptrs[j][k] == 0); } - JERRY_ASSERT (sizes[j] == 0 - || mem_heap_get_block_start (ptrs[j] + (size_t) rand () % sizes[j]) == ptrs[j]); + if (is_one_chunked[j]) + { + JERRY_ASSERT (sizes[j] == 0 + || mem_heap_get_chunked_block_start (ptrs[j] + (size_t) rand () % sizes[j]) == ptrs[j]); + } mem_heap_free_block (ptrs[j]);