@@ -66,6 +66,17 @@ typedef enum
66
66
MEM_BLOCK_ALLOCATED /* *< initializing allocated block */
67
67
} mem_block_state_t ;
68
68
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
+
69
80
/* *
70
81
* Linked list direction descriptors
71
82
*/
@@ -99,6 +110,7 @@ typedef struct __attribute__ ((aligned (MEM_ALIGNMENT))) mem_block_header_t
99
110
* 0 - if the block is the first block */
100
111
mem_heap_offset_t next_p : MEM_HEAP_OFFSET_LOG; /* *< next block's offset;
101
112
* 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) */
102
114
} mem_block_header_t ;
103
115
104
116
#if MEM_HEAP_OFFSET_LOG <= 16
@@ -145,6 +157,7 @@ static bool mem_is_block_free (const mem_block_header_t *block_header_p);
145
157
static void mem_init_block_header (uint8_t *first_chunk_p,
146
158
size_t size_in_chunks,
147
159
mem_block_state_t block_state,
160
+ mem_block_length_type_t length_type,
148
161
mem_block_header_t *prev_block_p,
149
162
mem_block_header_t *next_block_p);
150
163
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
263
276
JERRY_ASSERT (block_p->allocated_bytes == allocated_bytes);
264
277
} /* mem_set_block_allocated_bytes */
265
278
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
+
266
289
/* *
267
290
* Get block located at specified offset from specified block.
268
291
*
@@ -393,6 +416,7 @@ mem_heap_init (uint8_t *heap_start, /**< first address of heap space */
393
416
mem_init_block_header (mem_heap.heap_start ,
394
417
0 ,
395
418
MEM_BLOCK_FREE,
419
+ mem_block_length_type_t ::GENERAL,
396
420
NULL ,
397
421
NULL );
398
422
@@ -419,12 +443,13 @@ mem_heap_finalize (void)
419
443
} /* mem_heap_finalize */
420
444
421
445
/* *
422
- * Initialize block header
446
+ * Initialize block header located in the specified first chunk of the block
423
447
*/
424
448
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) */
428
453
mem_block_header_t *prev_block_p, /* *< previous block */
429
454
mem_block_header_t *next_block_p) /* *< next block */
430
455
{
@@ -435,12 +460,14 @@ mem_init_block_header (uint8_t *first_chunk_p, /**< address of the first
435
460
mem_set_block_prev (block_header_p, prev_block_p);
436
461
mem_set_block_next (block_header_p, next_block_p);
437
462
mem_set_block_allocated_bytes (block_header_p, allocated_bytes);
463
+ mem_set_block_set_length_type (block_header_p, length_type);
438
464
439
465
JERRY_ASSERT (allocated_bytes <= mem_get_block_data_space_size (block_header_p));
440
466
441
467
if (block_state == MEM_BLOCK_FREE)
442
468
{
443
469
JERRY_ASSERT (allocated_bytes == 0 );
470
+ JERRY_ASSERT (length_type == mem_block_length_type_t ::GENERAL);
444
471
JERRY_ASSERT (mem_is_block_free (block_header_p));
445
472
}
446
473
else
@@ -462,13 +489,17 @@ mem_init_block_header (uint8_t *first_chunk_p, /**< address of the first
462
489
* NULL - if there is not enough memory.
463
490
*/
464
491
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) */
466
495
mem_heap_alloc_term_t alloc_term) /* *< expected allocation term */
467
496
{
468
497
mem_block_header_t *block_p;
469
498
mem_direction_t direction;
470
499
471
500
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 ());
472
503
473
504
mem_check_heap ();
474
505
@@ -571,6 +602,7 @@ void* mem_heap_alloc_block_internal (size_t size_in_bytes, /**< size
571
602
mem_init_block_header (new_free_block_first_chunk_p,
572
603
0 ,
573
604
MEM_BLOCK_FREE,
605
+ mem_block_length_type_t ::GENERAL,
574
606
block_p,
575
607
next_block_p);
576
608
@@ -597,6 +629,7 @@ void* mem_heap_alloc_block_internal (size_t size_in_bytes, /**< size
597
629
mem_init_block_header ((uint8_t *) block_p,
598
630
size_in_bytes,
599
631
MEM_BLOCK_ALLOCATED,
632
+ length_type,
600
633
prev_block_p,
601
634
next_block_p);
602
635
@@ -620,60 +653,107 @@ void* mem_heap_alloc_block_internal (size_t size_in_bytes, /**< size
620
653
} /* mem_heap_alloc_block_internal */
621
654
622
655
/* *
623
- * Allocation of memory region.
656
+ * Allocation of memory region, running 'try to give memory back' callbacks, if there is not enough memory .
624
657
*
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.
626
660
*
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.
628
663
*
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.
631
665
*
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
634
670
*/
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 */
638
676
{
639
- if (unlikely ( size_in_bytes == 0 ) )
677
+ if (mem_heap. allocated_bytes + size_in_bytes >= mem_heap. limit )
640
678
{
641
- return NULL ;
679
+ mem_run_try_to_give_memory_back_callbacks (MEM_TRY_GIVE_MEMORY_BACK_SEVERITY_LOW) ;
642
680
}
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 ))
644
685
{
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
+ }
649
688
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);
651
696
652
- if (likely ( data_space_p != NULL ) )
697
+ if (data_space_p != NULL )
653
698
{
654
699
return data_space_p;
655
700
}
701
+ }
656
702
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 );
664
704
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 */
670
707
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);
674
731
}
675
732
} /* mem_heap_alloc_block */
676
733
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
+
677
757
/* *
678
758
* Free the memory block.
679
759
*/
@@ -844,6 +924,15 @@ mem_heap_get_block_start (void *ptr) /**< pointer into a block */
844
924
JERRY_UNREACHABLE ();
845
925
} /* mem_heap_get_block_start */
846
926
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
+
847
936
/* *
848
937
* Recommend allocation size based on chunk size.
849
938
*
@@ -965,6 +1054,9 @@ mem_check_heap (void)
965
1054
{
966
1055
VALGRIND_DEFINED_STRUCT (block_p);
967
1056
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
+
968
1060
chunk_sizes_sum += mem_get_block_chunks_count (block_p);
969
1061
970
1062
if (!mem_is_block_free (block_p))
0 commit comments