Skip to content

Commit 99ecdd4

Browse files
Introducing one-chunked heap blocks - special type for heap blocks that are guaranteed to fit into one heap chunk.
JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan [email protected]
1 parent 9763a93 commit 99ecdd4

File tree

2 files changed

+133
-39
lines changed

2 files changed

+133
-39
lines changed

jerry-core/mem/mem-heap.cpp

Lines changed: 131 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ typedef enum
6666
MEM_BLOCK_ALLOCATED /**< initializing allocated block */
6767
} mem_block_state_t;
6868

69+
/**
70+
* Length type of the block
71+
*
72+
* @see mem_init_block_header
73+
*/
74+
typedef enum class : uint8_t
75+
{
76+
ONE_CHUNKED, /**< one-chunked block (See also: mem_heap_alloc_chunked_block) */
77+
GENERAL /**< general (may be multi-chunk) block */
78+
} mem_block_length_type_t;
79+
6980
/**
7081
* Linked list direction descriptors
7182
*/
@@ -99,6 +110,7 @@ typedef struct __attribute__ ((aligned (MEM_ALIGNMENT))) mem_block_header_t
99110
* 0 - if the block is the first block */
100111
mem_heap_offset_t next_p : MEM_HEAP_OFFSET_LOG; /**< next block's offset;
101112
* 0 - if the block is the last block */
113+
mem_block_length_type_t length_type; /**< length type of the block (one-chunked or general) */
102114
} mem_block_header_t;
103115

104116
#if MEM_HEAP_OFFSET_LOG <= 16
@@ -145,6 +157,7 @@ static bool mem_is_block_free (const mem_block_header_t *block_header_p);
145157
static void mem_init_block_header (uint8_t *first_chunk_p,
146158
size_t size_in_chunks,
147159
mem_block_state_t block_state,
160+
mem_block_length_type_t length_type,
148161
mem_block_header_t *prev_block_p,
149162
mem_block_header_t *next_block_p);
150163
static void mem_check_heap (void);
@@ -263,6 +276,16 @@ mem_set_block_allocated_bytes (mem_block_header_t *block_p, /**< block to set al
263276
JERRY_ASSERT (block_p->allocated_bytes == allocated_bytes);
264277
} /* mem_set_block_allocated_bytes */
265278

279+
/**
280+
* Set the block's length type
281+
*/
282+
static void
283+
mem_set_block_set_length_type (mem_block_header_t *block_p, /**< block to set length type field for */
284+
mem_block_length_type_t length_type) /**< length type of the block */
285+
{
286+
block_p->length_type = length_type;
287+
} /* mem_set_block_set_length_type */
288+
266289
/**
267290
* Get block located at specified offset from specified block.
268291
*
@@ -393,6 +416,7 @@ mem_heap_init (uint8_t *heap_start, /**< first address of heap space */
393416
mem_init_block_header (mem_heap.heap_start,
394417
0,
395418
MEM_BLOCK_FREE,
419+
mem_block_length_type_t::GENERAL,
396420
NULL,
397421
NULL);
398422

@@ -419,12 +443,13 @@ mem_heap_finalize (void)
419443
} /* mem_heap_finalize */
420444

421445
/**
422-
* Initialize block header
446+
* Initialize block header located in the specified first chunk of the block
423447
*/
424448
static void
425-
mem_init_block_header (uint8_t *first_chunk_p, /**< address of the first chunk to use for the block */
426-
size_t allocated_bytes, /**< size of block's allocated area */
427-
mem_block_state_t block_state, /**< state of the block (allocated or free) */
449+
mem_init_block_header (uint8_t *first_chunk_p, /**< address of the first chunk to use for the block */
450+
size_t allocated_bytes, /**< size of block's allocated area */
451+
mem_block_state_t block_state, /**< state of the block (allocated or free) */
452+
mem_block_length_type_t length_type, /**< length type of the block (one-chunked or general) */
428453
mem_block_header_t *prev_block_p, /**< previous block */
429454
mem_block_header_t *next_block_p) /**< next block */
430455
{
@@ -435,12 +460,14 @@ mem_init_block_header (uint8_t *first_chunk_p, /**< address of the first
435460
mem_set_block_prev (block_header_p, prev_block_p);
436461
mem_set_block_next (block_header_p, next_block_p);
437462
mem_set_block_allocated_bytes (block_header_p, allocated_bytes);
463+
mem_set_block_set_length_type (block_header_p, length_type);
438464

439465
JERRY_ASSERT (allocated_bytes <= mem_get_block_data_space_size (block_header_p));
440466

441467
if (block_state == MEM_BLOCK_FREE)
442468
{
443469
JERRY_ASSERT (allocated_bytes == 0);
470+
JERRY_ASSERT (length_type == mem_block_length_type_t::GENERAL);
444471
JERRY_ASSERT (mem_is_block_free (block_header_p));
445472
}
446473
else
@@ -462,13 +489,17 @@ mem_init_block_header (uint8_t *first_chunk_p, /**< address of the first
462489
* NULL - if there is not enough memory.
463490
*/
464491
static
465-
void* mem_heap_alloc_block_internal (size_t size_in_bytes, /**< size of region to allocate in bytes */
492+
void* mem_heap_alloc_block_internal (size_t size_in_bytes, /**< size of region to allocate in bytes */
493+
mem_block_length_type_t length_type, /**< length type of the block
494+
* (one-chunked or general) */
466495
mem_heap_alloc_term_t alloc_term) /**< expected allocation term */
467496
{
468497
mem_block_header_t *block_p;
469498
mem_direction_t direction;
470499

471500
JERRY_ASSERT (size_in_bytes != 0);
501+
JERRY_ASSERT (length_type != mem_block_length_type_t::ONE_CHUNKED
502+
|| size_in_bytes == mem_heap_get_chunked_block_data_size ());
472503

473504
mem_check_heap ();
474505

@@ -571,6 +602,7 @@ void* mem_heap_alloc_block_internal (size_t size_in_bytes, /**< size
571602
mem_init_block_header (new_free_block_first_chunk_p,
572603
0,
573604
MEM_BLOCK_FREE,
605+
mem_block_length_type_t::GENERAL,
574606
block_p,
575607
next_block_p);
576608

@@ -597,6 +629,7 @@ void* mem_heap_alloc_block_internal (size_t size_in_bytes, /**< size
597629
mem_init_block_header ((uint8_t*) block_p,
598630
size_in_bytes,
599631
MEM_BLOCK_ALLOCATED,
632+
length_type,
600633
prev_block_p,
601634
next_block_p);
602635

@@ -620,60 +653,107 @@ void* mem_heap_alloc_block_internal (size_t size_in_bytes, /**< size
620653
} /* mem_heap_alloc_block_internal */
621654

622655
/**
623-
* Allocation of memory region.
656+
* Allocation of memory region, running 'try to give memory back' callbacks, if there is not enough memory.
624657
*
625-
* To reduce heap fragmentation there are two allocation modes - short-term and long-term.
658+
* Note:
659+
* if after running the callbacks, there is still not enough memory, engine is terminated with ERR_OUT_OF_MEMORY.
626660
*
627-
* If allocation is short-term then the beginning of the heap is preferred, else - the end of the heap.
661+
* Note:
662+
* To reduce heap fragmentation there are two allocation modes - short-term and long-term.
628663
*
629-
* It is supposed, that all short-term allocation is used during relatively short discrete sessions.
630-
* After end of the session all short-term allocated regions are supposed to be freed.
664+
* If allocation is short-term then the beginning of the heap is preferred, else - the end of the heap.
631665
*
632-
* @return pointer to allocated memory block - if allocation is successful,
633-
* NULL - if requested region size is zero or if there is not enough memory.
666+
* It is supposed, that all short-term allocation is used during relatively short discrete sessions.
667+
* After end of the session all short-term allocated regions are supposed to be freed.
668+
*
669+
* @return pointer to allocated memory block
634670
*/
635-
void*
636-
mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to allocate in bytes */
637-
mem_heap_alloc_term_t alloc_term) /**< expected allocation term */
671+
static void*
672+
mem_heap_alloc_block_try_give_memory_back (size_t size_in_bytes, /**< size of region to allocate in bytes */
673+
mem_block_length_type_t length_type, /**< length type of the block
674+
* (one-chunked or general) */
675+
mem_heap_alloc_term_t alloc_term) /**< expected allocation term */
638676
{
639-
if (unlikely (size_in_bytes == 0))
677+
if (mem_heap.allocated_bytes + size_in_bytes >= mem_heap.limit)
640678
{
641-
return NULL;
679+
mem_run_try_to_give_memory_back_callbacks (MEM_TRY_GIVE_MEMORY_BACK_SEVERITY_LOW);
642680
}
643-
else
681+
682+
void *data_space_p = mem_heap_alloc_block_internal (size_in_bytes, length_type, alloc_term);
683+
684+
if (likely (data_space_p != NULL))
644685
{
645-
if (mem_heap.allocated_bytes + size_in_bytes >= mem_heap.limit)
646-
{
647-
mem_run_try_to_give_memory_back_callbacks (MEM_TRY_GIVE_MEMORY_BACK_SEVERITY_LOW);
648-
}
686+
return data_space_p;
687+
}
649688

650-
void *data_space_p = mem_heap_alloc_block_internal (size_in_bytes, alloc_term);
689+
for (mem_try_give_memory_back_severity_t severity = MEM_TRY_GIVE_MEMORY_BACK_SEVERITY_LOW;
690+
severity <= MEM_TRY_GIVE_MEMORY_BACK_SEVERITY_CRITICAL;
691+
severity = (mem_try_give_memory_back_severity_t) (severity + 1))
692+
{
693+
mem_run_try_to_give_memory_back_callbacks (severity);
694+
695+
data_space_p = mem_heap_alloc_block_internal (size_in_bytes, length_type, alloc_term);
651696

652-
if (likely (data_space_p != NULL))
697+
if (data_space_p != NULL)
653698
{
654699
return data_space_p;
655700
}
701+
}
656702

657-
for (mem_try_give_memory_back_severity_t severity = MEM_TRY_GIVE_MEMORY_BACK_SEVERITY_LOW;
658-
severity <= MEM_TRY_GIVE_MEMORY_BACK_SEVERITY_CRITICAL;
659-
severity = (mem_try_give_memory_back_severity_t) (severity + 1))
660-
{
661-
mem_run_try_to_give_memory_back_callbacks (severity);
662-
663-
data_space_p = mem_heap_alloc_block_internal (size_in_bytes, alloc_term);
703+
JERRY_ASSERT (data_space_p == NULL);
664704

665-
if (data_space_p != NULL)
666-
{
667-
return data_space_p;
668-
}
669-
}
705+
jerry_fatal (ERR_OUT_OF_MEMORY);
706+
} /* mem_heap_alloc_block_try_give_memory_back */
670707

671-
JERRY_ASSERT (data_space_p == NULL);
672-
673-
jerry_fatal (ERR_OUT_OF_MEMORY);
708+
/**
709+
* Allocation of memory region.
710+
*
711+
* Note:
712+
* Please look at mem_heap_alloc_block_try_give_memory_back
713+
* for description of allocation term and out-of-memory handling.
714+
*
715+
* @return pointer to allocated memory block - if allocation is successful,
716+
* NULL - if requested region size is zero.
717+
*/
718+
void*
719+
mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to allocate in bytes */
720+
mem_heap_alloc_term_t alloc_term) /**< expected allocation term */
721+
{
722+
if (unlikely (size_in_bytes == 0))
723+
{
724+
return NULL;
725+
}
726+
else
727+
{
728+
return mem_heap_alloc_block_try_give_memory_back (size_in_bytes,
729+
mem_block_length_type_t::GENERAL,
730+
alloc_term);
674731
}
675732
} /* mem_heap_alloc_block */
676733

734+
/**
735+
* Allocation of one-chunked memory region, i.e. memory block that exactly fits one heap chunk.
736+
*
737+
* Note:
738+
* If there is any free space in the heap, it anyway can be allocated for one-chunked block.
739+
*
740+
* Contrariwise, there are cases, when block, requiring more than one chunk,
741+
* cannot be allocated, because of heap fragmentation.
742+
*
743+
* Note:
744+
* Please look at mem_heap_alloc_block_try_give_memory_back
745+
* for description of allocation term and out-of-memory handling.
746+
*
747+
* @return pointer to allocated memory block
748+
*/
749+
void*
750+
mem_heap_alloc_chunked_block (mem_heap_alloc_term_t alloc_term) /**< expected allocation term */
751+
{
752+
return mem_heap_alloc_block_try_give_memory_back (mem_heap_get_chunked_block_data_size (),
753+
mem_block_length_type_t::ONE_CHUNKED,
754+
alloc_term);
755+
} /* mem_heap_alloc_chunked_block */
756+
677757
/**
678758
* Free the memory block.
679759
*/
@@ -844,6 +924,15 @@ mem_heap_get_block_start (void *ptr) /**< pointer into a block */
844924
JERRY_UNREACHABLE ();
845925
} /* mem_heap_get_block_start */
846926

927+
/**
928+
* Get size of one-chunked block data space
929+
*/
930+
size_t
931+
mem_heap_get_chunked_block_data_size (void)
932+
{
933+
return (MEM_HEAP_CHUNK_SIZE - sizeof (mem_block_header_t));
934+
} /* mem_heap_get_chunked_block_data_size */
935+
847936
/**
848937
* Recommend allocation size based on chunk size.
849938
*
@@ -965,6 +1054,9 @@ mem_check_heap (void)
9651054
{
9661055
VALGRIND_DEFINED_STRUCT (block_p);
9671056

1057+
JERRY_ASSERT (block_p->length_type != mem_block_length_type_t::ONE_CHUNKED
1058+
|| block_p->allocated_bytes == mem_heap_get_chunked_block_data_size ());
1059+
9681060
chunk_sizes_sum += mem_get_block_chunks_count (block_p);
9691061

9701062
if (!mem_is_block_free (block_p))

jerry-core/mem/mem-heap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ typedef enum
4242
extern void mem_heap_init (uint8_t *heap_start, size_t heap_size);
4343
extern void mem_heap_finalize (void);
4444
extern void* mem_heap_alloc_block (size_t size_in_bytes, mem_heap_alloc_term_t alloc_term);
45+
extern void* mem_heap_alloc_chunked_block (mem_heap_alloc_term_t alloc_term);
4546
extern void mem_heap_free_block (void *ptr);
4647
extern void* mem_heap_get_block_start (void *ptr);
48+
extern size_t mem_heap_get_chunked_block_data_size (void);
4749
extern size_t __attr_pure___ mem_heap_recommend_allocation_size (size_t minimum_allocation_size);
4850
extern void mem_heap_print (bool dump_block_headers, bool dump_block_data, bool dump_stats);
4951

0 commit comments

Comments
 (0)