Allocate stack memory by chunks
This commit is contained in:
+172
-59
@@ -23,6 +23,11 @@
|
||||
DO NOT FORGET to free stack memory by calling STACK_FREE macro.
|
||||
For check usage of stack during a function, use STACK_DECLARE_USAGE and STACK_CHECK_USAGE macros.
|
||||
|
||||
For the purpose of memory fragmentation reduction, the memory is allocated by chunks and them are
|
||||
used to store data. The chunks are connected to each other in manner of double-linked list.
|
||||
|
||||
Macro STACK_CONVERT_TO_RAW_DATA allocates memory, so use it after finishing working with the stack.
|
||||
|
||||
Example (parser.c):
|
||||
|
||||
enum
|
||||
@@ -61,12 +66,22 @@
|
||||
#ifndef STACK_H
|
||||
#define STACK_H
|
||||
|
||||
#include "linked-list.h"
|
||||
|
||||
#define DEFINE_STACK_TYPE(NAME, DATA_TYPE, TYPE) \
|
||||
DEFINE_LINKED_LIST_TYPE (NAME, TYPE) \
|
||||
DEFINE_LIST_FREE (NAME) \
|
||||
DEFINE_LIST_ELEMENT (NAME, TYPE) \
|
||||
DEFINE_SET_LIST_ELEMENT (NAME, TYPE) \
|
||||
typedef TYPE NAME##_stack_value_type; \
|
||||
typedef DATA_TYPE NAME##_stack_data_type; \
|
||||
typedef struct \
|
||||
{ \
|
||||
DATA_TYPE length; \
|
||||
DATA_TYPE current; \
|
||||
TYPE *data; \
|
||||
DATA_TYPE block_len; \
|
||||
uint8_t *blocks; \
|
||||
uint8_t *last; \
|
||||
} \
|
||||
__packed \
|
||||
NAME##_stack;
|
||||
@@ -74,114 +89,212 @@ NAME##_stack;
|
||||
#define STACK_INIT(TYPE, NAME) \
|
||||
do { \
|
||||
size_t stack_size = mem_heap_recommend_allocation_size (sizeof (TYPE) * NAME##_global_size); \
|
||||
NAME.data = (TYPE *) mem_heap_alloc_block (stack_size, MEM_HEAP_ALLOC_SHORT_TERM); \
|
||||
NAME.blocks = NAME.last = mem_heap_alloc_block (stack_size, MEM_HEAP_ALLOC_SHORT_TERM); \
|
||||
__memset (NAME.blocks, 0, stack_size); \
|
||||
NAME.current = NAME##_global_size; \
|
||||
NAME.length = (__typeof__ (NAME.length)) (stack_size / sizeof (TYPE)); \
|
||||
NAME.length = NAME.block_len = (NAME##_stack_data_type) ((stack_size-sizeof (NAME##_linked_list)) / sizeof (TYPE)); \
|
||||
} while (0)
|
||||
|
||||
#define STACK_FREE(NAME) \
|
||||
do { \
|
||||
mem_heap_free_block ((uint8_t *) NAME.data); \
|
||||
free_##NAME##_linked_list (NAME.blocks); \
|
||||
NAME.length = NAME.current = 0; \
|
||||
} while (0)
|
||||
|
||||
/* In most cases (for example, in parser) default size of stack is enough.
|
||||
However, in serializer, there is a need for reallocation of memory.
|
||||
Do this in several steps:
|
||||
1) Allocate already allocated memory size twice.
|
||||
2) Copy used memory to the last.
|
||||
3) Dealocate first two chuncks.
|
||||
4) Allocate new memory. (It must point to the memory before increasing).
|
||||
5) Copy data back.
|
||||
6) Free temp buffer. */
|
||||
#define DEFINE_INCREASE_STACK_SIZE(NAME, TYPE) \
|
||||
static void increase_##NAME##_stack_size (__typeof__ (NAME.length)) __unused; \
|
||||
static void increase_##NAME##_stack_size (void) __unused; \
|
||||
static void \
|
||||
increase_##NAME##_stack_size (__typeof__ (NAME.length) elements_count) { \
|
||||
if (NAME.current + elements_count >= NAME.length) \
|
||||
increase_##NAME##_stack_size (void) { \
|
||||
if (NAME.current == NAME.length && ((NAME##_linked_list *) NAME.last)->next == NULL) \
|
||||
{ \
|
||||
size_t old_size = NAME.length * sizeof (TYPE); \
|
||||
size_t temp1_size = mem_heap_recommend_allocation_size ( \
|
||||
(size_t) (elements_count * sizeof (TYPE))); \
|
||||
size_t new_size = mem_heap_recommend_allocation_size ( \
|
||||
(size_t) (temp1_size + old_size)); \
|
||||
TYPE *temp1 = (TYPE *) mem_heap_alloc_block (temp1_size, MEM_HEAP_ALLOC_SHORT_TERM); \
|
||||
TYPE *temp2 = (TYPE *) mem_heap_alloc_block (old_size, MEM_HEAP_ALLOC_SHORT_TERM); \
|
||||
if (temp2 == NULL) \
|
||||
size_t temp_size = mem_heap_recommend_allocation_size ((size_t) (sizeof (NAME##_linked_list))); \
|
||||
JERRY_ASSERT ((temp_size-sizeof (NAME##_linked_list)) / sizeof (TYPE) == NAME.block_len); \
|
||||
NAME##_linked_list *temp = (NAME##_linked_list *) mem_heap_alloc_block ( \
|
||||
temp_size, MEM_HEAP_ALLOC_SHORT_TERM); \
|
||||
if (temp == NULL) \
|
||||
{ \
|
||||
mem_heap_print (true, false, true); \
|
||||
JERRY_UNREACHABLE (); \
|
||||
} \
|
||||
__memcpy (temp2, NAME.data, old_size); \
|
||||
mem_heap_free_block ((uint8_t *) NAME.data); \
|
||||
mem_heap_free_block ((uint8_t *) temp1); \
|
||||
NAME.data = (TYPE *) mem_heap_alloc_block (new_size, MEM_HEAP_ALLOC_SHORT_TERM); \
|
||||
if (NAME.data == NULL) \
|
||||
{ \
|
||||
__printf ("old_size: %d\ntemp1_size: %d\nnew_size: %d\n", old_size, temp1_size, new_size); \
|
||||
mem_heap_print (true, false, true); \
|
||||
JERRY_UNREACHABLE (); \
|
||||
} \
|
||||
__memcpy (NAME.data, temp2, old_size); \
|
||||
mem_heap_free_block ((uint8_t *) temp2); \
|
||||
NAME.length = (__typeof__ (NAME.length)) (new_size / sizeof (TYPE)); \
|
||||
__memset (temp, 0, temp_size); \
|
||||
((NAME##_linked_list *) NAME.last)->next = temp; \
|
||||
temp->prev = (NAME##_linked_list *) NAME.last; \
|
||||
NAME.last = (uint8_t *) temp; \
|
||||
NAME.length = (NAME##_stack_data_type) (NAME.length + NAME.block_len); \
|
||||
} \
|
||||
NAME.current = (__typeof__ (NAME.current)) (NAME.current + elements_count); \
|
||||
NAME.current = (NAME##_stack_data_type) (NAME.current + 1); \
|
||||
}
|
||||
|
||||
#define DEFINE_DECREASE_STACE_SIZE(NAME) \
|
||||
static void decrease_##NAME##_stack_size (__typeof__ (NAME.length)) __unused; \
|
||||
#define DEFINE_DECREASE_STACE_SIZE(NAME, TYPE) \
|
||||
static void decrease_##NAME##_stack_size (void) __unused; \
|
||||
static void \
|
||||
decrease_##NAME##_stack_size (__typeof__ (NAME.length) elements_count) { \
|
||||
JERRY_ASSERT (NAME.current - elements_count >= NAME##_global_size); \
|
||||
NAME.current = (__typeof__ (NAME.current)) (NAME.current - elements_count); \
|
||||
decrease_##NAME##_stack_size (void) { \
|
||||
JERRY_ASSERT (NAME.current - 1 >= NAME##_global_size); \
|
||||
NAME.current = (NAME##_stack_data_type) (NAME.current - 1); \
|
||||
}
|
||||
|
||||
#define DEFINE_STACK_ELEMENT(NAME, TYPE) \
|
||||
static TYPE NAME##_stack_element (NAME##_stack_data_type) __unused; \
|
||||
static TYPE NAME##_stack_element (NAME##_stack_data_type elem) { \
|
||||
JERRY_ASSERT (elem < NAME.current); \
|
||||
NAME##_linked_list *block = (NAME##_linked_list *) NAME.blocks; \
|
||||
for (NAME##_stack_data_type i = 0; i < elem / NAME.block_len; i++) { \
|
||||
JERRY_ASSERT (block->next); \
|
||||
block = block->next; \
|
||||
} \
|
||||
return NAME##_list_element ((uint8_t *) block, (uint8_t) ((elem)%NAME.block_len)); \
|
||||
}
|
||||
|
||||
#define DEFINE_SET_STACK_ELEMENT(NAME, TYPE) \
|
||||
static void set_##NAME##_stack_element (NAME##_stack_data_type, TYPE) __unused; \
|
||||
static void set_##NAME##_stack_element (NAME##_stack_data_type elem, TYPE value) { \
|
||||
JERRY_ASSERT (elem < NAME.current); \
|
||||
NAME##_linked_list *block = (NAME##_linked_list *) NAME.blocks; \
|
||||
for (NAME##_stack_data_type i = 0; i < elem / NAME.block_len; i++) { \
|
||||
JERRY_ASSERT (block->next); \
|
||||
block = block->next; \
|
||||
} \
|
||||
set_##NAME##_list_element ((uint8_t *) block, (uint8_t) ((elem)%NAME.block_len), value); \
|
||||
}
|
||||
|
||||
#define DEFINE_STACK_HEAD(NAME, TYPE) \
|
||||
static TYPE NAME##_stack_head (NAME##_stack_data_type) __unused; \
|
||||
static TYPE NAME##_stack_head (NAME##_stack_data_type elem) { \
|
||||
JERRY_ASSERT (elem <= NAME.current); \
|
||||
JERRY_ASSERT (elem <= NAME.block_len); \
|
||||
if ((NAME.current % NAME.block_len) < elem) { \
|
||||
return NAME##_list_element ((uint8_t *) ((NAME##_linked_list *) NAME.last)->prev, \
|
||||
(uint8_t) ((NAME.current % NAME.block_len) - elem + NAME.block_len)); \
|
||||
} else { \
|
||||
return NAME##_list_element (NAME.last, (uint8_t) ((NAME.current % NAME.block_len) - elem)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DEFINE_SET_STACK_HEAD(NAME, DATA_TYPE, TYPE) \
|
||||
static void set_##NAME##_stack_head (DATA_TYPE, TYPE) __unused; \
|
||||
static void set_##NAME##_stack_head (DATA_TYPE elem, TYPE value) { \
|
||||
JERRY_ASSERT (elem <= NAME.current); \
|
||||
JERRY_ASSERT (elem <= NAME.block_len); \
|
||||
if ((NAME.current % NAME.block_len) < elem) { \
|
||||
set_##NAME##_list_element ((uint8_t *) ((NAME##_linked_list *) NAME.last)->prev, \
|
||||
(uint8_t) ((NAME.current % NAME.block_len) - elem + NAME.block_len), value); \
|
||||
} else { \
|
||||
set_##NAME##_list_element (NAME.last, (uint8_t) ((NAME.current % NAME.block_len) - elem), value); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DEFINE_STACK_PUSH(NAME, TYPE) \
|
||||
static void NAME##_stack_push (TYPE) __unused; \
|
||||
static void NAME##_stack_push (TYPE value) { \
|
||||
if (NAME.current % NAME.block_len == 0 && NAME.current != 0) { \
|
||||
increase_##NAME##_stack_size (); \
|
||||
set_##NAME##_list_element (NAME.last, (uint8_t) ((NAME.current - 1) % NAME.block_len), value); \
|
||||
} else { \
|
||||
set_##NAME##_list_element (NAME.last, (uint8_t) ((NAME.current) % NAME.block_len), value); \
|
||||
increase_##NAME##_stack_size (); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DEFINE_CONVERT_TO_RAW_DATA(NAME, TYPE) \
|
||||
static TYPE *convert_##NAME##_to_raw_data (void) __unused; \
|
||||
static TYPE *convert_##NAME##_to_raw_data (void) { \
|
||||
size_t size = mem_heap_recommend_allocation_size ( \
|
||||
((size_t) (NAME.current + 1) * sizeof (NAME##_stack_value_type))); \
|
||||
TYPE *DATA = (TYPE *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM); \
|
||||
__memset (DATA, 0, size); \
|
||||
for (NAME##_stack_data_type i = 0; i < NAME.current; i++) { \
|
||||
DATA[i] = STACK_ELEMENT (NAME, i); \
|
||||
} \
|
||||
return DATA; \
|
||||
}
|
||||
|
||||
#define STACK_PUSH(NAME, VALUE) \
|
||||
do { \
|
||||
increase_##NAME##_stack_size (1); \
|
||||
NAME.data[NAME.current - 1] = VALUE; \
|
||||
} while (0)
|
||||
do { NAME##_stack_push (VALUE); } while (0)
|
||||
|
||||
#define STACK_POP(NAME, VALUE) \
|
||||
do { \
|
||||
decrease_##NAME##_stack_size (1); \
|
||||
VALUE = NAME.data[NAME.current]; \
|
||||
decrease_##NAME##_stack_size (); \
|
||||
VALUE = NAME##_list_element (NAME.last, (uint8_t) (NAME.current % NAME.block_len)); \
|
||||
} while (0)
|
||||
|
||||
#define STACK_DROP(NAME, I) \
|
||||
do { decrease_##NAME##_stack_size ((__typeof__(NAME.current))(I)); } while (0)
|
||||
do { \
|
||||
JERRY_ASSERT ((I) >= 0); \
|
||||
for (size_t i = 0; i < (size_t) (I); i++) { \
|
||||
decrease_##NAME##_stack_size (); } } while (0)
|
||||
|
||||
#define STACK_CLEAN(NAME) \
|
||||
STACK_DROP (NAME, NAME.current - NAME##_global_size);
|
||||
|
||||
#define STACK_HEAD(NAME, I) \
|
||||
NAME.data[NAME.current - I]
|
||||
NAME##_stack_head ((NAME##_stack_data_type) (I))
|
||||
|
||||
#define STACK_SET_HEAD(NAME, I, VALUE) \
|
||||
do { set_##NAME##_stack_head ((NAME##_stack_data_type) (I), VALUE); } while (0)
|
||||
|
||||
#define STACK_INCR_HEAD(NAME, I) \
|
||||
do { STACK_SET_HEAD (NAME, I, (NAME##_stack_value_type) (STACK_HEAD (NAME, I) + 1)); } while (0)
|
||||
|
||||
#define STACK_TOP(NAME) \
|
||||
STACK_HEAD (NAME, 1)
|
||||
|
||||
#define STACK_SWAP(NAME) \
|
||||
do { \
|
||||
NAME##_stack_value_type temp = STACK_TOP(NAME); \
|
||||
STACK_SET_HEAD(NAME, 1, STACK_HEAD(NAME, 2)); \
|
||||
STACK_SET_HEAD(NAME, 2, temp); \
|
||||
} while (0)
|
||||
|
||||
#define STACK_SIZE(NAME) \
|
||||
NAME.current
|
||||
|
||||
#define STACK_ELEMENT(NAME, I) \
|
||||
NAME.data[I]
|
||||
NAME##_stack_element ((NAME##_stack_data_type) (I))
|
||||
|
||||
#define STACK_RAW_DATA(NAME) \
|
||||
NAME.data
|
||||
#define STACK_SET_ELEMENT(NAME, I, VALUE) \
|
||||
do { set_##NAME##_stack_element ((NAME##_stack_data_type) I, VALUE); } while (0);
|
||||
|
||||
#define STACK_CONVERT_TO_RAW_DATA(NAME, DATA) \
|
||||
do { DATA = convert_##NAME##_to_raw_data (); } while (0)
|
||||
|
||||
#define STACK_INCR_ELEMENT(NAME, I) \
|
||||
do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT(NAME, I) + 1)); } while (0)
|
||||
|
||||
#define STACK_DECR_ELEMENT(NAME, I) \
|
||||
do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT(NAME, I) - 1)); } while (0)
|
||||
|
||||
#define STACK_ITERATE_VARG(NAME, FUNC, ...) \
|
||||
do { for (NAME##_stack_data_type i = 0; i < NAME.current; i++) { \
|
||||
FUNC (STACK_ELEMENT (NAME, i), __VA_ARGS__); \
|
||||
} } while (0)
|
||||
|
||||
#define STACK(NAME, DATA_TYPE, TYPE) \
|
||||
DEFINE_STACK_TYPE(NAME, DATA_TYPE, TYPE) \
|
||||
NAME##_stack NAME; \
|
||||
DEFINE_DECREASE_STACE_SIZE (NAME) \
|
||||
DEFINE_INCREASE_STACK_SIZE (NAME, TYPE)
|
||||
DEFINE_DECREASE_STACE_SIZE (NAME, TYPE) \
|
||||
DEFINE_INCREASE_STACK_SIZE (NAME, TYPE) \
|
||||
DEFINE_STACK_ELEMENT(NAME, TYPE) \
|
||||
DEFINE_SET_STACK_ELEMENT(NAME, TYPE) \
|
||||
DEFINE_STACK_HEAD(NAME, TYPE) \
|
||||
DEFINE_CONVERT_TO_RAW_DATA(NAME, TYPE) \
|
||||
DEFINE_SET_STACK_HEAD(NAME, DATA_TYPE, TYPE) \
|
||||
DEFINE_STACK_PUSH(NAME, TYPE)
|
||||
|
||||
#define STATIC_STACK(NAME, DATA_TYPE, TYPE) \
|
||||
DEFINE_STACK_TYPE(NAME, DATA_TYPE, TYPE) \
|
||||
static NAME##_stack NAME; \
|
||||
DEFINE_DECREASE_STACE_SIZE (NAME) \
|
||||
DEFINE_INCREASE_STACK_SIZE (NAME, TYPE)
|
||||
DEFINE_DECREASE_STACE_SIZE (NAME, TYPE) \
|
||||
DEFINE_INCREASE_STACK_SIZE (NAME, TYPE) \
|
||||
DEFINE_STACK_ELEMENT(NAME, TYPE) \
|
||||
DEFINE_SET_STACK_ELEMENT(NAME, TYPE) \
|
||||
DEFINE_STACK_HEAD(NAME, TYPE) \
|
||||
DEFINE_CONVERT_TO_RAW_DATA(NAME, TYPE) \
|
||||
DEFINE_SET_STACK_HEAD(NAME, DATA_TYPE, TYPE) \
|
||||
DEFINE_STACK_PUSH(NAME, TYPE)
|
||||
|
||||
#ifndef JERRY_NDEBUG
|
||||
#define STACK_DECLARE_USAGE(NAME) \
|
||||
__typeof__(NAME.current) NAME##_current = NAME.current;
|
||||
NAME##_stack_data_type NAME##_current = NAME.current;
|
||||
#define STACK_CHECK_USAGE(NAME) \
|
||||
do { \
|
||||
JERRY_ASSERT (NAME.current == NAME##_current); \
|
||||
|
||||
Reference in New Issue
Block a user