@@ -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);
145157static 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);
150163static 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 */
424448static 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 */
464491static
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_with_try_to_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);
664-
665- if (data_space_p != NULL )
666- {
667- return data_space_p;
668- }
669- }
703+ JERRY_ASSERT (data_space_p == NULL );
670704
671- JERRY_ASSERT (data_space_p == NULL );
705+ jerry_fatal (ERR_OUT_OF_MEMORY);
706+ } /* mem_heap_alloc_block_with_try_to_give_memory_back */
672707
673- jerry_fatal (ERR_OUT_OF_MEMORY);
708+ /* *
709+ * Allocation of memory region.
710+ *
711+ * Note:
712+ * Please look at mem_heap_alloc_block_with_try_to_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_with_try_to_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_with_try_to_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_with_try_to_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 __attr_pure___
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,11 @@ mem_check_heap (void)
9651054 {
9661055 VALGRIND_DEFINED_STRUCT (block_p);
9671056
1057+ if (block_p->length_type == mem_block_length_type_t ::ONE_CHUNKED)
1058+ {
1059+ JERRY_ASSERT (block_p->allocated_bytes == mem_heap_get_chunked_block_data_size ());
1060+ }
1061+
9681062 chunk_sizes_sum += mem_get_block_chunks_count (block_p);
9691063
9701064 if (!mem_is_block_free (block_p))
0 commit comments