From da47dedaed381ab846b215099172f6ad1335572a Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Thu, 1 Sep 2016 01:44:08 -0700 Subject: [PATCH] Add 32 bit compressed pointer support. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- docs/04.INTERNALS.md | 9 +- jerry-core/CMakeLists.txt | 7 ++ jerry-core/config.h | 14 --- jerry-core/ecma/base/ecma-alloc.c | 24 ++--- jerry-core/ecma/base/ecma-globals.h | 11 ++ jerry-core/ecma/base/ecma-helpers-value.c | 5 +- jerry-core/ecma/base/ecma-helpers.c | 60 ++++++++--- jerry-core/ecma/base/ecma-literal-storage.c | 13 ++- jerry-core/jcontext/jcontext.h | 5 +- jerry-core/jmem/jmem-allocator.c | 50 ++++++++- jerry-core/jmem/jmem-allocator.h | 47 +++++--- jerry-core/jmem/jmem-config.h | 10 -- jerry-core/jmem/jmem-heap.c | 52 +-------- jerry-core/jmem/jmem-heap.h | 2 - jerry-core/jmem/jmem-poolman.c | 112 +++++++++++++++----- jerry-core/jmem/jmem-poolman.h | 4 +- jerry-core/vm/vm-stack.c | 2 +- tests/unit/test-poolman.c | 13 +-- tools/build.py | 2 + 19 files changed, 270 insertions(+), 172 deletions(-) diff --git a/docs/04.INTERNALS.md b/docs/04.INTERNALS.md index 7f5b9e70f1..cac2f92cfc 100644 --- a/docs/04.INTERNALS.md +++ b/docs/04.INTERNALS.md @@ -243,10 +243,11 @@ Compressed pointers were introduced to save heap space. ![Compressed Pointer](img/ecma_compressed.png) -These pointers are 8 byte aligned 16 bit long pointers which can address 512 Kb of memory which is also the maximum size of the JerryScript heap. - -ECMA data elements are allocated in pools (pools are allocated on heap) -Chunk size of the pool is 8 bytes (reduces fragmentation). +These pointers are 8 byte aligned 16 bit long pointers which can address 512 Kb of +memory which is also the maximum size of the JerryScript heap. To support even more +memory the size of compressed pointers can be extended to 32 bit to cover the entire +address space of a 32 bit system by passing "--cpointer_32_bit on" to the build +system. These "uncompressed pointers" increases the memory consumption by around 20%. ### Number diff --git a/jerry-core/CMakeLists.txt b/jerry-core/CMakeLists.txt index 5b5291ce7b..ecec9f1b80 100644 --- a/jerry-core/CMakeLists.txt +++ b/jerry-core/CMakeLists.txt @@ -22,6 +22,7 @@ set(FEATURE_PROFILE "full" CACHE STRING "Profile types: full, minimal") set(FEATURE_ERROR_MESSAGES OFF CACHE BOOL "Enable error messages?") set(FEATURE_VALGRIND OFF CACHE BOOL "Enable Valgrind support?") set(FEATURE_VALGRIND_FREYA OFF CACHE BOOL "Enable Valgrind-Freya support?") +set(FEATURE_CPOINTER_32_BIT OFF CACHE BOOL "Enable 32 bit compressed pointers?") set(FEATURE_MEM_STRESS_TEST OFF CACHE BOOL "Enable mem-stress test?") set(FEATURE_MEM_STATS OFF CACHE BOOL "Enable memory statistics?") set(FEATURE_PARSER_DUMP OFF CACHE BOOL "Enable parser byte-code dumps?") @@ -35,6 +36,7 @@ message(STATUS "FEATURE_PROFILE " ${FEATURE_PROFILE}) message(STATUS "FEATURE_ERROR_MESSAGES " ${FEATURE_ERROR_MESSAGES}) message(STATUS "FEATURE_VALGRIND " ${FEATURE_VALGRIND}) message(STATUS "FEATURE_VALGRIND_FREYA " ${FEATURE_VALGRIND_FREYA}) +message(STATUS "FEATURE_CPOINTER_32_BIT " ${FEATURE_CPOINTER_32_BIT}) message(STATUS "FEATURE_MEM_STRESS_TEST " ${FEATURE_MEM_STRESS_TEST}) message(STATUS "FEATURE_MEM_STATS " ${FEATURE_MEM_STATS}) message(STATUS "FEATURE_PARSER_DUMP " ${FEATURE_PARSER_DUMP}) @@ -182,6 +184,11 @@ if(FEATURE_VALGRIND_FREYA) set(INCLUDE_CORE ${INCLUDE_CORE} ${INCLUDE_THIRD_PARTY_VALGRIND}) endif() +# Enable 32 bit cpointers +if(FEATURE_CPOINTER_32_BIT) + set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_CPOINTER_32_BIT) +endif() + # Memory management stress-test mode if(FEATURE_MEM_STRESS_TEST) set(DEFINES_JERRY ${DEFINES_JERRY} JMEM_GC_BEFORE_EACH_ALLOC) diff --git a/jerry-core/config.h b/jerry-core/config.h index 01fa1c693c..0dcec31c6b 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -39,8 +39,6 @@ */ #ifndef CONFIG_MEM_HEAP_AREA_SIZE # define CONFIG_MEM_HEAP_AREA_SIZE (512 * 1024) -#elif CONFIG_MEM_HEAP_AREA_SIZE > (512 * 1024) -# error "Currently, maximum 512 kilobytes heap size is supported" #endif /* !CONFIG_MEM_HEAP_AREA_SIZE */ /** @@ -53,18 +51,6 @@ */ #define CONFIG_MEM_HEAP_DESIRED_LIMIT (JERRY_MIN (CONFIG_MEM_HEAP_AREA_SIZE / 32, CONFIG_MEM_HEAP_MAX_LIMIT)) -/** - * Log2 of maximum possible offset in the heap - * - * The option affects size of compressed pointer that in turn - * affects size of ECMA Object Model's data types. - * - * In any case size of any of the types should not exceed CONFIG_MEM_POOL_CHUNK_SIZE. - * - * On the other hand, value 2 ^ CONFIG_MEM_HEAP_OFFSET_LOG should not be less than CONFIG_MEM_HEAP_AREA_SIZE. - */ -#define CONFIG_MEM_HEAP_OFFSET_LOG (19) - /** * Number of lower bits in key of literal hash table. */ diff --git a/jerry-core/ecma/base/ecma-alloc.c b/jerry-core/ecma/base/ecma-alloc.c index 71239d33f1..8ecf888b6c 100644 --- a/jerry-core/ecma/base/ecma-alloc.c +++ b/jerry-core/ecma/base/ecma-alloc.c @@ -25,22 +25,9 @@ JERRY_STATIC_ASSERT (sizeof (ecma_property_value_t) == sizeof (ecma_value_t), size_of_ecma_property_value_t_must_be_equal_to_size_of_ecma_value_t); JERRY_STATIC_ASSERT (((sizeof (ecma_property_value_t) - 1) & sizeof (ecma_property_value_t)) == 0, size_of_ecma_property_value_t_must_be_power_of_2); -JERRY_STATIC_ASSERT (sizeof (ecma_property_pair_t) == sizeof (uint64_t) * 2, - size_of_ecma_property_pair_t_must_be_equal_to_16_bytes); -JERRY_STATIC_ASSERT (sizeof (ecma_object_t) <= sizeof (uint64_t), - size_of_ecma_object_t_must_be_less_than_or_equal_to_8_bytes); -JERRY_STATIC_ASSERT (sizeof (ecma_extended_object_t) <= sizeof (uint64_t) * 2, - size_of_ecma_extended_object_t_must_be_less_than_or_equal_to_16_bytes); - -JERRY_STATIC_ASSERT (sizeof (ecma_collection_header_t) == sizeof (uint64_t), - size_of_ecma_collection_header_t_must_be_less_than_or_equal_to_8_bytes); -JERRY_STATIC_ASSERT (sizeof (ecma_collection_chunk_t) == sizeof (uint64_t), - size_of_ecma_collection_chunk_t_must_be_less_than_or_equal_to_8_bytes); JERRY_STATIC_ASSERT (sizeof (ecma_string_t) == sizeof (uint64_t), size_of_ecma_string_t_must_be_less_than_or_equal_to_8_bytes); -JERRY_STATIC_ASSERT (sizeof (ecma_getter_setter_pointers_t) <= sizeof (uint64_t), - size_of_ecma_getter_setter_pointers_t_must_be_less_than_or_equal_to_8_bytes); /** \addtogroup ecma ECMA * @{ @@ -67,20 +54,21 @@ JERRY_STATIC_ASSERT (sizeof (ecma_getter_setter_pointers_t) <= sizeof (uint64_t) #define ALLOC(ecma_type) ecma_ ## ecma_type ## _t * \ ecma_alloc_ ## ecma_type (void) \ { \ - ecma_ ## ecma_type ## _t *p ## ecma_type = (ecma_ ## ecma_type ## _t *) jmem_pools_alloc (); \ + ecma_ ## ecma_type ## _t *ecma_type ## _p; \ + ecma_type ## _p = (ecma_ ## ecma_type ## _t *) jmem_pools_alloc (sizeof (ecma_ ## ecma_type ## _t)); \ \ - JERRY_ASSERT (p ## ecma_type != NULL); \ + JERRY_ASSERT (ecma_type ## _p != NULL); \ \ - return p ## ecma_type; \ + return ecma_type ## _p; \ } /** * Deallocation routine template */ #define DEALLOC(ecma_type) void \ - ecma_dealloc_ ## ecma_type (ecma_ ## ecma_type ## _t *p ## ecma_type) \ + ecma_dealloc_ ## ecma_type (ecma_ ## ecma_type ## _t *ecma_type ## _p) \ { \ - jmem_pools_free ((uint8_t *) p ## ecma_type); \ + jmem_pools_free ((uint8_t *) ecma_type ## _p, sizeof (ecma_ ## ecma_type ## _t)); \ } /** diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 113ef36d7a..3dbe77b1fc 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -361,9 +361,16 @@ typedef struct */ typedef struct { +#ifdef JERRY_CPOINTER_32_BIT + jmem_cpointer_t next_property_cp; /**< next cpointer */ +#endif /* JERRY_CPOINTER_32_BIT */ ecma_property_t types[ECMA_PROPERTY_PAIR_ITEM_COUNT]; /**< two property type slot. The first represent * the type of this property (e.g. property pair) */ +#ifdef JERRY_CPOINTER_32_BIT + uint16_t padding; /**< an unused value */ +#else /* !JERRY_CPOINTER_32_BIT */ jmem_cpointer_t next_property_cp; /**< next cpointer */ +#endif /* JERRY_CPOINTER_32_BIT */ } ecma_property_header_t; /** @@ -381,7 +388,11 @@ typedef struct typedef union { ecma_value_t value; /**< value of a property */ +#ifdef JERRY_CPOINTER_32_BIT + jmem_cpointer_t getter_setter_pair_cp; /**< cpointer to getter setter pair */ +#else /* !JERRY_CPOINTER_32_BIT */ ecma_getter_setter_pointers_t getter_setter_pair; /**< getter setter pair */ +#endif /* JERRY_CPOINTER_32_BIT */ } ecma_property_value_t; /** diff --git a/jerry-core/ecma/base/ecma-helpers-value.c b/jerry-core/ecma/base/ecma-helpers-value.c index 19554d9863..76b4330e4e 100644 --- a/jerry-core/ecma/base/ecma-helpers-value.c +++ b/jerry-core/ecma/base/ecma-helpers-value.c @@ -43,9 +43,8 @@ JERRY_STATIC_ASSERT ((ECMA_VALUE_FULL_MASK + 1) == (1 << ECMA_VALUE_SHIFT), JERRY_STATIC_ASSERT (ECMA_VALUE_SHIFT <= JMEM_ALIGNMENT_LOG, ecma_value_shift_must_be_less_than_or_equal_than_mem_alignment_log); -JERRY_STATIC_ASSERT ((sizeof (ecma_value_t) * JERRY_BITSINBYTE) - >= (sizeof (jmem_cpointer_t) * JERRY_BITSINBYTE + ECMA_VALUE_SHIFT), - ecma_value_must_be_large_enough_to_store_compressed_pointers); +JERRY_STATIC_ASSERT (sizeof (jmem_cpointer_t) <= sizeof (ecma_value_t), + size_of_jmem_cpointer_t_must_be_less_or_equal_to_the_size_of_ecma_value_t); #ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index e99885d845..2395bca489 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -613,8 +613,16 @@ ecma_create_named_accessor_property (ecma_object_t *object_p, /**< object */ ecma_ref_ecma_string (name_p); ecma_property_value_t value; +#ifdef JERRY_CPOINTER_32_BIT + ecma_getter_setter_pointers_t *getter_setter_pair_p; + getter_setter_pair_p = jmem_pools_alloc (sizeof (ecma_getter_setter_pointers_t)); + ECMA_SET_POINTER (getter_setter_pair_p->getter_p, get_p); + ECMA_SET_POINTER (getter_setter_pair_p->setter_p, set_p); + ECMA_SET_POINTER (value.getter_setter_pair_cp, getter_setter_pair_p); +#else /* !JERRY_CPOINTER_32_BIT */ ECMA_SET_POINTER (value.getter_setter_pair.getter_p, get_p); ECMA_SET_POINTER (value.getter_setter_pair.setter_p, set_p); +#endif /* JERRY_CPOINTER_32_BIT */ return ecma_create_property (object_p, name_p, type_and_flags, value); } /* ecma_create_named_accessor_property */ @@ -763,20 +771,6 @@ ecma_get_named_data_property (ecma_object_t *obj_p, /**< object to find property return property_p; } /* ecma_get_named_data_property */ -/** - * Free the named data property and values it references. - */ -static void -ecma_free_named_data_property (ecma_object_t *object_p, /**< object the property belongs to */ - ecma_property_t *property_p) /**< the property */ -{ - JERRY_ASSERT (object_p != NULL); - JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_GET_TYPE (property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); - - ecma_value_t v = ecma_get_named_data_property_value (property_p); - ecma_free_value_if_not_object (v); -} /* ecma_free_named_data_property */ - /** * Free the internal property and values it references. */ @@ -873,7 +867,8 @@ ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to { case ECMA_PROPERTY_TYPE_NAMEDDATA: { - ecma_free_named_data_property (object_p, property_p); + ecma_free_value_if_not_object (ecma_get_named_data_property_value (property_p)); + if (ecma_is_property_lcached (property_p)) { ecma_lcache_invalidate (object_p, name_p, property_p); @@ -882,6 +877,13 @@ ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to } case ECMA_PROPERTY_TYPE_NAMEDACCESSOR: { +#ifdef JERRY_CPOINTER_32_BIT + ecma_getter_setter_pointers_t *getter_setter_pair_p; + getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t, + ECMA_PROPERTY_VALUE_PTR (property_p)->getter_setter_pair_cp); + jmem_pools_free (getter_setter_pair_p, sizeof (ecma_getter_setter_pointers_t)); +#endif /* JERRY_CPOINTER_32_BIT */ + if (ecma_is_property_lcached (property_p)) { ecma_lcache_invalidate (object_p, name_p, property_p); @@ -1083,7 +1085,14 @@ ecma_get_named_accessor_property_getter (const ecma_property_t *prop_p) /**< nam { JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); +#ifdef JERRY_CPOINTER_32_BIT + ecma_getter_setter_pointers_t *getter_setter_pair_p; + getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t, + ECMA_PROPERTY_VALUE_PTR (prop_p)->getter_setter_pair_cp); + return ECMA_GET_POINTER (ecma_object_t, getter_setter_pair_p->getter_p); +#else /* !JERRY_CPOINTER_32_BIT */ return ECMA_GET_POINTER (ecma_object_t, ECMA_PROPERTY_VALUE_PTR (prop_p)->getter_setter_pair.getter_p); +#endif /* JERRY_CPOINTER_32_BIT */ } /* ecma_get_named_accessor_property_getter */ /** @@ -1096,7 +1105,14 @@ ecma_get_named_accessor_property_setter (const ecma_property_t *prop_p) /**< nam { JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); +#ifdef JERRY_CPOINTER_32_BIT + ecma_getter_setter_pointers_t *getter_setter_pair_p; + getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t, + ECMA_PROPERTY_VALUE_PTR (prop_p)->getter_setter_pair_cp); + return ECMA_GET_POINTER (ecma_object_t, getter_setter_pair_p->setter_p); +#else /* !JERRY_CPOINTER_32_BIT */ return ECMA_GET_POINTER (ecma_object_t, ECMA_PROPERTY_VALUE_PTR (prop_p)->getter_setter_pair.setter_p); +#endif /* JERRY_CPOINTER_32_BIT */ } /* ecma_get_named_accessor_property_setter */ /** @@ -1110,7 +1126,14 @@ ecma_set_named_accessor_property_getter (ecma_object_t *object_p, /**< the prope JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); ecma_assert_object_contains_the_property (object_p, prop_p); +#ifdef JERRY_CPOINTER_32_BIT + ecma_getter_setter_pointers_t *getter_setter_pair_p; + getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t, + ECMA_PROPERTY_VALUE_PTR (prop_p)->getter_setter_pair_cp); + ECMA_SET_POINTER (getter_setter_pair_p->getter_p, getter_p); +#else /* !JERRY_CPOINTER_32_BIT */ ECMA_SET_POINTER (ECMA_PROPERTY_VALUE_PTR (prop_p)->getter_setter_pair.getter_p, getter_p); +#endif /* JERRY_CPOINTER_32_BIT */ } /* ecma_set_named_accessor_property_getter */ /** @@ -1124,7 +1147,14 @@ ecma_set_named_accessor_property_setter (ecma_object_t *object_p, /**< the prope JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); ecma_assert_object_contains_the_property (object_p, prop_p); +#ifdef JERRY_CPOINTER_32_BIT + ecma_getter_setter_pointers_t *getter_setter_pair_p; + getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t, + ECMA_PROPERTY_VALUE_PTR (prop_p)->getter_setter_pair_cp); + ECMA_SET_POINTER (getter_setter_pair_p->setter_p, setter_p); +#else /* !JERRY_CPOINTER_32_BIT */ ECMA_SET_POINTER (ECMA_PROPERTY_VALUE_PTR (prop_p)->getter_setter_pair.setter_p, setter_p); +#endif /* JERRY_CPOINTER_32_BIT */ } /* ecma_set_named_accessor_property_setter */ /** diff --git a/jerry-core/ecma/base/ecma-literal-storage.c b/jerry-core/ecma/base/ecma-literal-storage.c index 2dc08398ce..317f1d475c 100644 --- a/jerry-core/ecma/base/ecma-literal-storage.c +++ b/jerry-core/ecma/base/ecma-literal-storage.c @@ -25,9 +25,6 @@ * @{ */ -JERRY_STATIC_ASSERT (sizeof (ecma_lit_storage_item_t) <= sizeof (uint64_t), - size_of_ecma_lit_storage_item_t_must_be_less_than_or_equal_to_8_bytes); - /** * Free string list */ @@ -50,7 +47,7 @@ ecma_free_string_list (ecma_lit_storage_item_t *string_list_p) /**< string list ecma_lit_storage_item_t *prev_item = string_list_p; string_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, string_list_p->next_cp); - jmem_pools_free (prev_item); + jmem_pools_free (prev_item, sizeof (ecma_lit_storage_item_t)); } } /* ecma_free_string_list */ @@ -115,7 +112,8 @@ ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string return result; } - ecma_lit_storage_item_t *new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (); + ecma_lit_storage_item_t *new_item_p; + new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (sizeof (ecma_lit_storage_item_t)); new_item_p->values[0] = result; for (int i = 1; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) @@ -182,7 +180,7 @@ ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be number_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, number_list_p->next_cp); } - ecma_string_t *string_p = (ecma_string_t *) jmem_pools_alloc (); + ecma_string_t *string_p = (ecma_string_t *) jmem_pools_alloc (sizeof (ecma_string_t)); string_p->refs_and_container = ECMA_STRING_REF_ONE | ECMA_STRING_LITERAL_NUMBER; string_p->u.lit_number = num; @@ -195,7 +193,8 @@ ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be return result; } - ecma_lit_storage_item_t *new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (); + ecma_lit_storage_item_t *new_item_p; + new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (sizeof (ecma_lit_storage_item_t)); new_item_p->values[0] = result; for (int i = 1; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 17d4518708..0927110672 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -54,7 +54,10 @@ typedef struct ecma_object_t *ecma_gc_objects_lists[ECMA_GC_COLOR__COUNT]; /**< List of marked (visited during * current GC session) and umarked objects */ jmem_heap_free_t *jmem_heap_list_skip_p; /**< This is used to speed up deallocation. */ - jmem_pools_chunk_t *jmem_free_chunk_p; /**< list of free pool chunks */ + jmem_pools_chunk_t *jmem_free_8_byte_chunk_p; /**< list of free eight byte pool chunks */ +#ifdef JERRY_CPOINTER_32_BIT + jmem_pools_chunk_t *jmem_free_16_byte_chunk_p; /**< list of free sixteen byte pool chunks */ +#endif /* JERRY_CPOINTER_32_BIT */ jmem_free_unused_memory_callback_t jmem_free_unused_memory_callback; /**< Callback for freeing up memory. */ const lit_utf8_byte_t **lit_magic_string_ex_array; /**< array of external magic strings */ const lit_utf8_size_t *lit_magic_string_ex_sizes; /**< external magic string lengths */ diff --git a/jerry-core/jmem/jmem-allocator.c b/jerry-core/jmem/jmem-allocator.c index ec1343e4bb..a61c65818f 100644 --- a/jerry-core/jmem/jmem-allocator.c +++ b/jerry-core/jmem/jmem-allocator.c @@ -27,6 +27,14 @@ #define JMEM_ALLOCATOR_INTERNAL #include "jmem-allocator-internal.h" +#ifdef JERRY_CPOINTER_32_BIT + +/* This check will go away when we will support 64 bit compressed pointers. */ +JERRY_STATIC_ASSERT (sizeof (uintptr_t) <= sizeof (jmem_cpointer_t), + size_of_uintpt_t_must_be_equal_to_jmem_cpointer_t); + +#endif + /** * Initialize memory allocators. */ @@ -59,12 +67,29 @@ jmem_finalize () * * @return packed pointer */ -uintptr_t +inline jmem_cpointer_t __attr_always_inline___ jmem_compress_pointer (const void *pointer_p) /**< pointer to compress */ { + JERRY_ASSERT (pointer_p != NULL); JERRY_ASSERT (jmem_is_heap_pointer (pointer_p)); - return jmem_heap_compress_pointer (pointer_p); + uintptr_t uint_ptr = (uintptr_t) pointer_p; + + JERRY_ASSERT (uint_ptr % JMEM_ALIGNMENT == 0); + +#ifdef JERRY_CPOINTER_32_BIT + JERRY_ASSERT (((jmem_cpointer_t) uint_ptr) == uint_ptr); +#else /* !JERRY_CPOINTER_32_BIT */ + const uintptr_t heap_start = (uintptr_t) &JERRY_HEAP_CONTEXT (first); + + uint_ptr -= heap_start; + uint_ptr >>= JMEM_ALIGNMENT_LOG; + + JERRY_ASSERT (uint_ptr <= UINT16_MAX); + JERRY_ASSERT (uint_ptr != JMEM_CP_NULL); +#endif /* JERRY_CPOINTER_32_BIT */ + + return (jmem_cpointer_t) uint_ptr; } /* jmem_compress_pointer */ /** @@ -72,10 +97,27 @@ jmem_compress_pointer (const void *pointer_p) /**< pointer to compress */ * * @return unpacked pointer */ -void * +inline void * __attr_always_inline___ jmem_decompress_pointer (uintptr_t compressed_pointer) /**< pointer to decompress */ { - return jmem_heap_decompress_pointer (compressed_pointer); + JERRY_ASSERT (compressed_pointer != JMEM_CP_NULL); + + uintptr_t uint_ptr = compressed_pointer; + + JERRY_ASSERT (((jmem_cpointer_t) uint_ptr) == uint_ptr); + +#ifdef JERRY_CPOINTER_32_BIT + JERRY_ASSERT (uint_ptr % JMEM_ALIGNMENT == 0); +#else /* !JERRY_CPOINTER_32_BIT */ + const uintptr_t heap_start = (uintptr_t) &JERRY_HEAP_CONTEXT (first); + + uint_ptr <<= JMEM_ALIGNMENT_LOG; + uint_ptr += heap_start; + + JERRY_ASSERT (jmem_is_heap_pointer ((void *) uint_ptr)); +#endif /* JERRY_CPOINTER_32_BIT */ + + return (void *) uint_ptr; } /* jmem_decompress_pointer */ /** diff --git a/jerry-core/jmem/jmem-allocator.h b/jerry-core/jmem/jmem-allocator.h index e7921b866e..4b8a04869f 100644 --- a/jerry-core/jmem/jmem-allocator.h +++ b/jerry-core/jmem/jmem-allocator.h @@ -29,29 +29,52 @@ */ /** - * Compressed pointer + * Compressed pointer representations + * + * 16 bit representation: + * The jmem_cpointer_t is defined as uint16_t + * and it can contain any sixteen bit value. + * + * 32 bit representation: + * The jmem_cpointer_t is defined as uint32_t. + * The lower JMEM_ALIGNMENT_LOG bits must be zero. + * The other bits can have any value. + * + * The 16 bit representation always encodes an offset from + * a heap base. The 32 bit representation currently encodes + * raw 32 bit JMEM_ALIGNMENT aligned pointers on 32 bit systems. + * This can be extended to encode a 32 bit offset from a heap + * base on 64 bit systems in the future. There are no plans + * to support more than 4G address space for JerryScript. */ -typedef uint16_t jmem_cpointer_t; /** - * Representation of NULL value for compressed pointers + * Compressed pointer */ -#define JMEM_CP_NULL ((jmem_cpointer_t) 0) +#ifdef JERRY_CPOINTER_32_BIT +typedef uint32_t jmem_cpointer_t; +#else /* !JERRY_CPOINTER_32_BIT */ +typedef uint16_t jmem_cpointer_t; +#endif /* JERRY_CPOINTER_32_BIT */ /** - * Required alignment for allocated units/blocks + * Width of compressed memory pointer */ -#define JMEM_ALIGNMENT (1u << JMEM_ALIGNMENT_LOG) +#ifdef JERRY_CPOINTER_32_BIT +#define JMEM_CP_WIDTH 32 +#else /* !JERRY_CPOINTER_32_BIT */ +#define JMEM_CP_WIDTH 16 +#endif /* JERRY_CPOINTER_32_BIT */ /** - * Width of compressed memory pointer + * Representation of NULL value for compressed pointers */ -#define JMEM_CP_WIDTH (JMEM_HEAP_OFFSET_LOG - JMEM_ALIGNMENT_LOG) +#define JMEM_CP_NULL ((jmem_cpointer_t) 0) /** - * Compressed pointer value mask + * Required alignment for allocated units/blocks */ -#define JMEM_CP_MASK ((1ull << JMEM_CP_WIDTH) - 1) +#define JMEM_ALIGNMENT (1u << JMEM_ALIGNMENT_LOG) /** * Severity of a 'try give memory back' request @@ -107,7 +130,7 @@ typedef void (*jmem_free_unused_memory_callback_t) (jmem_free_unused_memory_seve * to specified non_compressed_pointer */ #define JMEM_CP_SET_NON_NULL_POINTER(cp_value, non_compressed_pointer) \ - (cp_value) = (jmem_compress_pointer (non_compressed_pointer) & JMEM_CP_MASK) + (cp_value) = jmem_compress_pointer (non_compressed_pointer) /** * Set value of compressed pointer so that it will correspond @@ -131,7 +154,7 @@ typedef void (*jmem_free_unused_memory_callback_t) (jmem_free_unused_memory_seve extern void jmem_init (void); extern void jmem_finalize (void); -extern uintptr_t jmem_compress_pointer (const void *); +extern jmem_cpointer_t jmem_compress_pointer (const void *); extern void *jmem_decompress_pointer (uintptr_t); extern void jmem_register_free_unused_memory_callback (jmem_free_unused_memory_callback_t); diff --git a/jerry-core/jmem/jmem-config.h b/jerry-core/jmem/jmem-config.h index a3e4d836e1..790970016c 100644 --- a/jerry-core/jmem/jmem-config.h +++ b/jerry-core/jmem/jmem-config.h @@ -18,21 +18,11 @@ #include "config.h" -/** - * Log2 of maximum possible offset in the heap - */ -#define JMEM_HEAP_OFFSET_LOG (CONFIG_MEM_HEAP_OFFSET_LOG) - /** * Size of heap */ #define JMEM_HEAP_SIZE ((size_t) (CONFIG_MEM_HEAP_AREA_SIZE)) -/** - * Size of pool chunk - */ -#define JMEM_POOL_CHUNK_SIZE ((size_t) (CONFIG_MEM_POOL_CHUNK_SIZE)) - /** * Logarithm of required alignment for allocated units/blocks */ diff --git a/jerry-core/jmem/jmem-heap.c b/jerry-core/jmem/jmem-heap.c index 4a39956f24..523e15c0ef 100644 --- a/jerry-core/jmem/jmem-heap.c +++ b/jerry-core/jmem/jmem-heap.c @@ -145,8 +145,10 @@ static void jmem_heap_stat_free_iter (); void jmem_heap_init (void) { - JERRY_STATIC_ASSERT ((1u << JMEM_HEAP_OFFSET_LOG) >= JMEM_HEAP_SIZE, - two_pow_mem_heap_offset_should_not_be_less_than_mem_heap_size); +#ifndef JERRY_CPOINTER_32_BIT + JERRY_STATIC_ASSERT (((UINT16_MAX + 1) << JMEM_ALIGNMENT_LOG) >= JMEM_HEAP_SIZE, + maximum_heap_size_for_16_bit_compressed_pointers_is_512K); +#endif /* !JERRY_CPOINTER_32_BIT */ JERRY_ASSERT ((uintptr_t) JERRY_HEAP_CONTEXT (area) % JMEM_ALIGNMENT == 0); @@ -521,52 +523,6 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the JMEM_HEAP_STAT_FREE (size); } /* jmem_heap_free_block */ -/** - * Compress pointer - * - * @return packed heap pointer - */ -uintptr_t __attr_pure___ __attribute__((hot)) -jmem_heap_compress_pointer (const void *pointer_p) /**< pointer to compress */ -{ - JERRY_ASSERT (pointer_p != NULL); - JERRY_ASSERT (jmem_is_heap_pointer (pointer_p)); - - uintptr_t int_ptr = (uintptr_t) pointer_p; - const uintptr_t heap_start = (uintptr_t) &JERRY_HEAP_CONTEXT (first); - - JERRY_ASSERT (int_ptr % JMEM_ALIGNMENT == 0); - - int_ptr -= heap_start; - int_ptr >>= JMEM_ALIGNMENT_LOG; - - JERRY_ASSERT ((int_ptr & ~((1u << JMEM_HEAP_OFFSET_LOG) - 1)) == 0); - - JERRY_ASSERT (int_ptr != JMEM_CP_NULL); - - return int_ptr; -} /* jmem_heap_compress_pointer */ - -/** - * Decompress pointer - * - * @return unpacked heap pointer - */ -void * __attr_pure___ __attribute__((hot)) -jmem_heap_decompress_pointer (uintptr_t compressed_pointer) /**< pointer to decompress */ -{ - JERRY_ASSERT (compressed_pointer != JMEM_CP_NULL); - - uintptr_t int_ptr = compressed_pointer; - const uintptr_t heap_start = (uintptr_t) &JERRY_HEAP_CONTEXT (first); - - int_ptr <<= JMEM_ALIGNMENT_LOG; - int_ptr += heap_start; - - JERRY_ASSERT (jmem_is_heap_pointer ((void *) int_ptr)); - return (void *) int_ptr; -} /* jmem_heap_decompress_pointer */ - #ifndef JERRY_NDEBUG /** * Check whether the pointer points to the heap diff --git a/jerry-core/jmem/jmem-heap.h b/jerry-core/jmem/jmem-heap.h index ebde6bae0f..ac06121c5a 100644 --- a/jerry-core/jmem/jmem-heap.h +++ b/jerry-core/jmem/jmem-heap.h @@ -34,8 +34,6 @@ extern void jmem_heap_finalize (void); extern void *jmem_heap_alloc_block (const size_t); extern void *jmem_heap_alloc_block_null_on_error (const size_t); extern void jmem_heap_free_block (void *, const size_t); -extern uintptr_t jmem_heap_compress_pointer (const void *); -extern void *jmem_heap_decompress_pointer (uintptr_t); extern bool jmem_is_heap_pointer (const void *); #ifdef JMEM_STATS diff --git a/jerry-core/jmem/jmem-poolman.c b/jerry-core/jmem/jmem-poolman.c index 6170da079f..0c548f29fa 100644 --- a/jerry-core/jmem/jmem-poolman.c +++ b/jerry-core/jmem/jmem-poolman.c @@ -77,9 +77,6 @@ static void jmem_pools_stat_dealloc (void); # define VALGRIND_FREYA_FREELIKE_SPACE(p) #endif /* JERRY_VALGRIND_FREYA */ -JERRY_STATIC_ASSERT (sizeof (jmem_pools_chunk_t) <= JMEM_POOL_CHUNK_SIZE, - size_of_mem_pools_chunk_t_must_be_less_than_or_equal_to_MEM_POOL_CHUNK_SIZE); - /** * Finalize pool manager */ @@ -88,7 +85,10 @@ jmem_pools_finalize (void) { jmem_pools_collect_empty (); - JERRY_ASSERT (JERRY_CONTEXT (jmem_free_chunk_p) == NULL); + JERRY_ASSERT (JERRY_CONTEXT (jmem_free_8_byte_chunk_p) == NULL); +#ifdef JERRY_CPOINTER_32_BIT + JERRY_ASSERT (JERRY_CONTEXT (jmem_free_16_byte_chunk_p) == NULL); +#endif /* JERRY_CPOINTER_32_BIT */ } /* jmem_pools_finalize */ /** @@ -98,49 +98,94 @@ jmem_pools_finalize (void) * or NULL - if not enough memory. */ inline void * __attribute__((hot)) __attr_always_inline___ -jmem_pools_alloc (void) +jmem_pools_alloc (size_t size) /**< size of the chunk */ { #ifdef JMEM_GC_BEFORE_EACH_ALLOC jmem_run_free_unused_memory_callbacks (JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH); #endif /* JMEM_GC_BEFORE_EACH_ALLOC */ - if (JERRY_CONTEXT (jmem_free_chunk_p) != NULL) + if (size <= 8) { - const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_chunk_p); + if (JERRY_CONTEXT (jmem_free_8_byte_chunk_p) != NULL) + { + const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_8_byte_chunk_p); + + JMEM_POOLS_STAT_REUSE (); + + VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); + + JERRY_CONTEXT (jmem_free_8_byte_chunk_p) = chunk_p->next_p; + + VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); + + return (void *) chunk_p; + } + else + { + JMEM_POOLS_STAT_NEW_ALLOC (); + return (void *) jmem_heap_alloc_block (8); + } + } + +#ifdef JERRY_CPOINTER_32_BIT + JERRY_ASSERT (size <= 16); + + if (JERRY_CONTEXT (jmem_free_16_byte_chunk_p) != NULL) + { + const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_16_byte_chunk_p); JMEM_POOLS_STAT_REUSE (); - VALGRIND_DEFINED_SPACE (chunk_p, JMEM_POOL_CHUNK_SIZE); + VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); - JERRY_CONTEXT (jmem_free_chunk_p) = chunk_p->next_p; + JERRY_CONTEXT (jmem_free_16_byte_chunk_p) = chunk_p->next_p; - VALGRIND_UNDEFINED_SPACE (chunk_p, JMEM_POOL_CHUNK_SIZE); + VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); return (void *) chunk_p; } else { JMEM_POOLS_STAT_NEW_ALLOC (); - return (void *) jmem_heap_alloc_block (JMEM_POOL_CHUNK_SIZE); + return (void *) jmem_heap_alloc_block (16); } +#else /* !JERRY_CPOINTER_32_BIT */ + JERRY_UNREACHABLE (); + return NULL; +#endif } /* jmem_pools_alloc */ /** * Free the chunk */ -void __attribute__((hot)) -jmem_pools_free (void *chunk_p) /**< pointer to the chunk */ +inline void __attribute__((hot)) __attr_always_inline___ +jmem_pools_free (void *chunk_p, /**< pointer to the chunk */ + size_t size) /**< size of the chunk */ { JERRY_ASSERT (chunk_p != NULL); jmem_pools_chunk_t *const chunk_to_free_p = (jmem_pools_chunk_t *) chunk_p; - VALGRIND_DEFINED_SPACE (chunk_to_free_p, JMEM_POOL_CHUNK_SIZE); + VALGRIND_DEFINED_SPACE (chunk_to_free_p, size); - chunk_to_free_p->next_p = JERRY_CONTEXT (jmem_free_chunk_p); - JERRY_CONTEXT (jmem_free_chunk_p) = chunk_to_free_p; + if (size <= 8) + { + chunk_to_free_p->next_p = JERRY_CONTEXT (jmem_free_8_byte_chunk_p); + JERRY_CONTEXT (jmem_free_8_byte_chunk_p) = chunk_to_free_p; + } + else + { +#ifdef JERRY_CPOINTER_32_BIT + JERRY_ASSERT (size <= 16); + + chunk_to_free_p->next_p = JERRY_CONTEXT (jmem_free_16_byte_chunk_p); + JERRY_CONTEXT (jmem_free_16_byte_chunk_p) = chunk_to_free_p; +#else /* !JERRY_CPOINTER_32_BIT */ + JERRY_UNREACHABLE (); +#endif /* JERRY_CPOINTER_32_BIT */ + } - VALGRIND_NOACCESS_SPACE (chunk_to_free_p, JMEM_POOL_CHUNK_SIZE); + VALGRIND_NOACCESS_SPACE (chunk_to_free_p, size); JMEM_POOLS_STAT_FREE_POOL (); } /* jmem_pools_free */ @@ -151,16 +196,35 @@ jmem_pools_free (void *chunk_p) /**< pointer to the chunk */ void jmem_pools_collect_empty () { - while (JERRY_CONTEXT (jmem_free_chunk_p)) + jmem_pools_chunk_t *chunk_p = JERRY_CONTEXT (jmem_free_8_byte_chunk_p); + JERRY_CONTEXT (jmem_free_8_byte_chunk_p) = NULL; + + while (chunk_p) + { + VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); + jmem_pools_chunk_t *const next_p = chunk_p->next_p; + VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); + + jmem_heap_free_block (chunk_p, 8); + JMEM_POOLS_STAT_DEALLOC (); + chunk_p = next_p; + } + +#ifdef JERRY_CPOINTER_32_BIT + chunk_p = JERRY_CONTEXT (jmem_free_16_byte_chunk_p); + JERRY_CONTEXT (jmem_free_16_byte_chunk_p) = NULL; + + while (chunk_p) { - VALGRIND_DEFINED_SPACE (JERRY_CONTEXT (jmem_free_chunk_p), sizeof (jmem_pools_chunk_t)); - jmem_pools_chunk_t *const next_p = JERRY_CONTEXT (jmem_free_chunk_p)->next_p; - VALGRIND_NOACCESS_SPACE (JERRY_CONTEXT (jmem_free_chunk_p), sizeof (jmem_pools_chunk_t)); + VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); + jmem_pools_chunk_t *const next_p = chunk_p->next_p; + VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); - jmem_heap_free_block (JERRY_CONTEXT (jmem_free_chunk_p), JMEM_POOL_CHUNK_SIZE); + jmem_heap_free_block (chunk_p, 16); JMEM_POOLS_STAT_DEALLOC (); - JERRY_CONTEXT (jmem_free_chunk_p) = next_p; + chunk_p = next_p; } +#endif /* JERRY_CPOINTER_32_BIT */ } /* jmem_pools_collect_empty */ #ifdef JMEM_STATS @@ -193,12 +257,10 @@ jmem_pools_stats_print (void) jmem_pools_stats_t *pools_stats = &JERRY_CONTEXT (jmem_pools_stats); JERRY_DEBUG_MSG ("Pools stats:\n" - " Chunk size: %zu\n" " Pool chunks: %zu\n" " Peak pool chunks: %zu\n" " Free chunks: %zu\n" " Pool reuse ratio: %zu.%04zu\n", - JMEM_POOL_CHUNK_SIZE, pools_stats->pools_count, pools_stats->peak_pools_count, pools_stats->free_chunks, diff --git a/jerry-core/jmem/jmem-poolman.h b/jerry-core/jmem/jmem-poolman.h index ca0ec1984b..f63f0a6a32 100644 --- a/jerry-core/jmem/jmem-poolman.h +++ b/jerry-core/jmem/jmem-poolman.h @@ -30,8 +30,8 @@ */ extern void jmem_pools_finalize (void); -extern void *jmem_pools_alloc (void); -extern void jmem_pools_free (void *); +extern void *jmem_pools_alloc (size_t); +extern void jmem_pools_free (void *, size_t); extern void jmem_pools_collect_empty (void); #ifdef JMEM_STATS diff --git a/jerry-core/vm/vm-stack.c b/jerry-core/vm/vm-stack.c index 4d48a2bbd3..860c6ee7ea 100644 --- a/jerry-core/vm/vm-stack.c +++ b/jerry-core/vm/vm-stack.c @@ -68,7 +68,7 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ } case VM_CONTEXT_FOR_IN: { - jmem_cpointer_t current = (uint16_t) vm_stack_top_p[-2]; + jmem_cpointer_t current = (jmem_cpointer_t) vm_stack_top_p[-2]; while (current != JMEM_CP_NULL) { diff --git a/tests/unit/test-poolman.c b/tests/unit/test-poolman.c index a951b2f5ac..36a6d9be3a 100644 --- a/tests/unit/test-poolman.c +++ b/tests/unit/test-poolman.c @@ -30,9 +30,10 @@ const uint32_t test_iters = 1024; // Subiterations count #define TEST_MAX_SUB_ITERS 1024 +#define TEST_CHUNK_SIZE 8 uint8_t *ptrs[TEST_MAX_SUB_ITERS]; -uint8_t data[TEST_MAX_SUB_ITERS][JMEM_POOL_CHUNK_SIZE]; +uint8_t data[TEST_MAX_SUB_ITERS][TEST_CHUNK_SIZE]; int main () @@ -47,16 +48,16 @@ main () for (size_t j = 0; j < subiters; j++) { - ptrs[j] = (uint8_t *) jmem_pools_alloc (); + ptrs[j] = (uint8_t *) jmem_pools_alloc (TEST_CHUNK_SIZE); if (ptrs[j] != NULL) { - for (size_t k = 0; k < JMEM_POOL_CHUNK_SIZE; k++) + for (size_t k = 0; k < TEST_CHUNK_SIZE; k++) { ptrs[j][k] = (uint8_t) (rand () % 256); } - memcpy (data[j], ptrs[j], JMEM_POOL_CHUNK_SIZE); + memcpy (data[j], ptrs[j], TEST_CHUNK_SIZE); } } @@ -71,9 +72,9 @@ main () if (ptrs[j] != NULL) { - TEST_ASSERT (!memcmp (data[j], ptrs[j], JMEM_POOL_CHUNK_SIZE)); + TEST_ASSERT (!memcmp (data[j], ptrs[j], TEST_CHUNK_SIZE)); - jmem_pools_free (ptrs[j]); + jmem_pools_free (ptrs[j], TEST_CHUNK_SIZE); } } } diff --git a/tools/build.py b/tools/build.py index 8908216199..3425343ca1 100755 --- a/tools/build.py +++ b/tools/build.py @@ -42,6 +42,7 @@ def add_build_args(parser): parser.add_argument('--error-messages', choices=['on', 'off'], default='off', help='Enable error messages (default: %(default)s)') parser.add_argument('--valgrind', choices=['on', 'off'], default='off', help='Enable Valgrind support (default: %(default)s)') parser.add_argument('--valgrind-freya', choices=['on', 'off'], default='off', help='Enable Valgrind-Freya support (default: %(default)s)') + parser.add_argument('--cpointer_32_bit', choices=['on', 'off'], default='off', help='Enable 32 bit compressed pointers (default: %(default)s)') parser.add_argument('--show-opcodes', choices=['on', 'off'], default='off', help='Enable parser byte-code dumps (default: %(default)s)') parser.add_argument('--show-regexp-opcodes', choices=['on', 'off'], default='off', help='Enable regexp byte-code dumps (default: %(default)s)') parser.add_argument('--mem-stats', choices=['on', 'off'], default='off', help='Enable memory statistics (default: %(default)s)') @@ -78,6 +79,7 @@ def generate_build_options(arguments): build_options.append('-DFEATURE_VALGRIND_FREYA=%s' % arguments.valgrind_freya.upper()) build_options.append('-DFEATURE_PARSER_DUMP=%s' % arguments.show_opcodes.upper()) build_options.append('-DFEATURE_REGEXP_DUMP=%s' % arguments.show_regexp_opcodes.upper()) + build_options.append('-DFEATURE_CPOINTER_32_BIT=%s' % arguments.cpointer_32_bit.upper()) build_options.append('-DFEATURE_MEM_STATS=%s' % arguments.mem_stats.upper()) build_options.append('-DFEATURE_MEM_STRESS_TEST=%s' % arguments.mem_stress_test.upper()) build_options.append('-DFEATURE_SNAPSHOT_SAVE=%s' % arguments.snapshot_save.upper())