From e7ec053362a275cecabdd282fab35e660b761938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20K=C3=A1d=C3=A1r?= Date: Mon, 4 Jul 2016 13:26:23 +0200 Subject: [PATCH] More gc-friendly property hashmap allocation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New allocator is added that returns null on out of memory, property hasmap create uses this allocator for now. - Property hashmaps of objects are removed durring a high severity gc. Follow up patch is in progress. JerryScript-DCO-1.0-Signed-off-by: István Kádár ikadar@inf.u-szeged.hu --- jerry-core/ecma/base/ecma-gc.c | 26 ++++++++-- jerry-core/ecma/base/ecma-gc.h | 2 +- jerry-core/ecma/base/ecma-init-finalize.c | 2 +- jerry-core/ecma/base/ecma-property-hashmap.c | 8 ++- jerry-core/jerry.c | 2 +- jerry-core/jmem/jmem-heap.c | 52 ++++++++++++++++++-- jerry-core/jmem/jmem-heap.h | 1 + 7 files changed, 81 insertions(+), 12 deletions(-) diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 1e7c28dce..bc62a35a3 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -506,7 +506,7 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ * Run garbage collection */ void -ecma_gc_run (void) +ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */ { ecma_gc_new_objects_since_last_gc = 0; @@ -577,6 +577,26 @@ ecma_gc_run (void) ecma_gc_sweep (obj_iter_p); } + if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH) + { + /* Remove the property hashmap of BLACK objects */ + for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK], *obj_next_p; + obj_iter_p != NULL; + obj_iter_p = obj_next_p) + { + obj_next_p = ecma_gc_get_object_next (obj_iter_p); + + JERRY_ASSERT (ecma_gc_is_object_visited (obj_iter_p)); + + ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_iter_p); + if (prop_iter_p != NULL + && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP) + { + ecma_property_hashmap_free (obj_iter_p); + } + } + } + /* Unmarking all objects */ ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY] = ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK]; ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK] = NULL; @@ -603,7 +623,7 @@ ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< sever */ if (ecma_gc_new_objects_since_last_gc * CONFIG_ECMA_GC_NEW_OBJECTS_SHARE_TO_START_GC > ecma_gc_objects_number) { - ecma_gc_run (); + ecma_gc_run (severity); } } else @@ -611,7 +631,7 @@ ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< sever JERRY_ASSERT (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH); /* Freeing as much memory as we currently can */ - ecma_gc_run (); + ecma_gc_run (severity); } } /* ecma_free_unused_memory */ diff --git a/jerry-core/ecma/base/ecma-gc.h b/jerry-core/ecma/base/ecma-gc.h index 8e891d8b1..1d62b2b8d 100644 --- a/jerry-core/ecma/base/ecma-gc.h +++ b/jerry-core/ecma/base/ecma-gc.h @@ -30,7 +30,7 @@ extern void ecma_gc_init (void); extern void ecma_init_gc_info (ecma_object_t *); extern void ecma_ref_object (ecma_object_t *); extern void ecma_deref_object (ecma_object_t *); -extern void ecma_gc_run (void); +extern void ecma_gc_run (jmem_free_unused_memory_severity_t); extern void ecma_free_unused_memory (jmem_free_unused_memory_severity_t); /** diff --git a/jerry-core/ecma/base/ecma-init-finalize.c b/jerry-core/ecma/base/ecma-init-finalize.c index 6fedd456b..fbddf251b 100644 --- a/jerry-core/ecma/base/ecma-init-finalize.c +++ b/jerry-core/ecma/base/ecma-init-finalize.c @@ -54,7 +54,7 @@ ecma_finalize (void) ecma_finalize_environment (); ecma_finalize_builtins (); - ecma_gc_run (); + ecma_gc_run (JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW); ecma_finalize_lit_storage (); } /* ecma_finalize */ diff --git a/jerry-core/ecma/base/ecma-property-hashmap.c b/jerry-core/ecma/base/ecma-property-hashmap.c index 549984bc6..4c3110ffa 100644 --- a/jerry-core/ecma/base/ecma-property-hashmap.c +++ b/jerry-core/ecma/base/ecma-property-hashmap.c @@ -110,7 +110,13 @@ ecma_property_hashmap_create (ecma_object_t *object_p) /**< object */ size_t total_size = ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE (max_property_count); - ecma_property_hashmap_t *hashmap_p = (ecma_property_hashmap_t *) jmem_heap_alloc_block (total_size); + ecma_property_hashmap_t *hashmap_p = (ecma_property_hashmap_t *) jmem_heap_alloc_block_null_on_error (total_size); + + if (hashmap_p == NULL) + { + return; + } + memset (hashmap_p, 0, total_size); hashmap_p->header.types[0].type_and_flags = ECMA_PROPERTY_TYPE_HASHMAP; diff --git a/jerry-core/jerry.c b/jerry-core/jerry.c index 57e62afaa..d4273773f 100644 --- a/jerry-core/jerry.c +++ b/jerry-core/jerry.c @@ -224,7 +224,7 @@ jerry_gc (void) { jerry_assert_api_available (); - ecma_gc_run (); + ecma_gc_run (JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW); } /* jerry_gc */ /** diff --git a/jerry-core/jmem/jmem-heap.c b/jerry-core/jmem/jmem-heap.c index 41e0aa172..461964768 100644 --- a/jerry-core/jmem/jmem-heap.c +++ b/jerry-core/jmem/jmem-heap.c @@ -321,12 +321,17 @@ void *jmem_heap_alloc_block_internal (const size_t size) * Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory. * * Note: - * if after running the callbacks, there is still not enough memory, engine is terminated with ERR_OUT_OF_MEMORY. + * if there is still not enough memory after running the callbacks + * - NULL value will be returned if parmeter 'ret_null_on_error' is true + * - the engine will terminate with ERR_OUT_OF_MEMORY if 'ret_null_on_error' is false * - * @return pointer to allocated memory block + * @return NULL, if the required memory size is 0 + * also NULL, if 'ret_null_on_error' is true and the allocation fails because of there is not enough memory */ -void * __attribute__((hot)) -jmem_heap_alloc_block (const size_t size) +static void * +jmem_heap_gc_and_alloc_block (const size_t size, /**< required memory size */ + bool ret_null_on_error) /**< indicates whether return null or terminate + with ERR_OUT_OF_MEMORY on out of memory */ { if (unlikely (size == 0)) { @@ -369,9 +374,46 @@ jmem_heap_alloc_block (const size_t size) JERRY_ASSERT (data_space_p == NULL); - jerry_fatal (ERR_OUT_OF_MEMORY); + if (!ret_null_on_error) + { + jerry_fatal (ERR_OUT_OF_MEMORY); + } + + return data_space_p; +} /* jmem_heap_gc_and_alloc_block */ + +/** + * Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory. + * + * Note: + * If there is still not enough memory after running the callbacks, then the engine will be + * terminated with ERR_OUT_OF_MEMORY. + * + * @return NULL, if the required memory is 0 + * pointer to allocated memory block, otherwise + */ +void * __attribute__((hot)) __attr_always_inline___ +jmem_heap_alloc_block (const size_t size) /**< required memory size */ +{ + return jmem_heap_gc_and_alloc_block (size, false); } /* jmem_heap_alloc_block */ +/** + * Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory. + * + * Note: + * If there is still not enough memory after running the callbacks, NULL will be returned. + * + * @return NULL, if the required memory size is 0 + * also NULL, if the allocation has failed + * pointer to the allocated memory block, otherwise + */ +void * __attribute__((hot)) __attr_always_inline___ +jmem_heap_alloc_block_null_on_error (const size_t size) /**< required memory size */ +{ + return jmem_heap_gc_and_alloc_block (size, true); +} /* jmem_heap_alloc_block_null_on_error */ + /** * Allocate block and store block size. * diff --git a/jerry-core/jmem/jmem-heap.h b/jerry-core/jmem/jmem-heap.h index 812892d60..5dba09543 100644 --- a/jerry-core/jmem/jmem-heap.h +++ b/jerry-core/jmem/jmem-heap.h @@ -32,6 +32,7 @@ extern void jmem_heap_init (void); 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 void *jmem_heap_alloc_block_store_size (size_t); extern void jmem_heap_free_block_size_stored (void *);