From ff22634e27602d0bae6bc40e32f24259410f0a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20B=C3=A1tyai?= Date: Wed, 17 Jul 2019 14:12:23 +0200 Subject: [PATCH] Refactor memory management (#2954) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR is a general cleanup for garbage collection and memory allocation code paths. Changes: * Removed an unnecesary local variable from 'ecma_gc_mark'. * Refactored 'ecma_gc_run' to have an implicit list head during iteration, which results in one less condition in the loops, and changed the loops to use compressed pointers to reduce the overall amount of compression/decompression. * Renamed 'jmem_free_unused_memory_severity_t' to 'jmem_pressure_t', and added additional values. * Removed 'jmem_free_unused_memory_callback', instead 'ecma_free_unused_memory' is now called directly. * Reworked 'ecma_free_unused_memory' to handle all code paths related to 'jmem_pressure_t', and moved all relevant code paths into this function. This simplifies the code paths in other places. * Reworked 'jmem_heap_gc_and_alloc_block' to be more streamlined. * Changed mem-stats to not report unused pool chunks as allocated memory. * Created an allocator internal API for allocating/freeing memory blocks that are not reported as used memory in mem-stats. * Removed iteration statistics for the jerry allocator from mem-stats, as they don't provide any actually useful information. Co-authored-by: Marko Fabo JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu --- docs/02.API-REFERENCE.md | 8 +- docs/10.EXT-REFERENCE-HANDLER.md | 2 +- docs/14.EXT-REFERENCE-HANDLE-SCOPE.md | 4 +- jerry-core/api/jerry.c | 10 +- jerry-core/ecma/base/ecma-gc.c | 234 ++++++++-------- jerry-core/ecma/base/ecma-gc.h | 4 +- jerry-core/ecma/base/ecma-globals.h | 2 +- jerry-core/ecma/base/ecma-init-finalize.c | 7 +- jerry-core/include/jerryscript-core.h | 4 +- jerry-core/jcontext/jcontext.h | 11 +- jerry-core/jmem/jmem-allocator-internal.h | 30 ++- jerry-core/jmem/jmem-allocator.c | 37 --- jerry-core/jmem/jmem-heap.c | 253 ++++++------------ jerry-core/jmem/jmem-poolman.c | 25 +- jerry-core/jmem/jmem.h | 38 +-- jerry-ext/handler/handler-gc.c | 4 +- tests/unit-core/test-api.c | 2 +- tests/unit-core/test-heap.c | 126 --------- tests/unit-core/test-objects-foreach.c | 4 +- tests/unit-ext/test-ext-autorelease.c | 2 +- tests/unit-ext/test-ext-handle-scope-escape.c | 4 +- ...t-ext-handle-scope-handle-prelist-escape.c | 4 +- .../test-ext-handle-scope-handle-prelist.c | 4 +- tests/unit-ext/test-ext-handle-scope-nested.c | 4 +- tests/unit-ext/test-ext-handle-scope-remove.c | 6 +- tests/unit-ext/test-ext-handle-scope-root.c | 4 +- tests/unit-ext/test-ext-handle-scope.c | 2 +- 27 files changed, 297 insertions(+), 538 deletions(-) delete mode 100644 tests/unit-core/test-heap.c diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 52affee62..4135049ff 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -87,10 +87,10 @@ Option bits for [jerry_parse](#jerry_parse) and Set garbage collection operational mode - - JERRY_GC_SEVERITY_LOW - free unused objects - - JERRY_GC_SEVERITY_HIGH - free as much memory as possible + - JERRY_GC_PRESSURE_LOW - free unused objects + - JERRY_GC_PRESSURE_HIGH - free as much memory as possible -The difference between `JERRY_GC_SEVERITY_LOW` and `JERRY_GC_SEVERITY_HIGH` +The difference between `JERRY_GC_PRESSURE_LOW` and `JERRY_GC_PRESSURE_HIGH` is that the former keeps memory allocated for performance improvements such as property hash tables for large objects. The latter frees all possible memory blocks but the performance may drop after the garbage collection. @@ -844,7 +844,7 @@ main (void) jerry_value_t object_value = jerry_create_object (); jerry_release_value (object_value); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); jerry_cleanup (); } diff --git a/docs/10.EXT-REFERENCE-HANDLER.md b/docs/10.EXT-REFERENCE-HANDLER.md index c942cea17..193f29e40 100644 --- a/docs/10.EXT-REFERENCE-HANDLER.md +++ b/docs/10.EXT-REFERENCE-HANDLER.md @@ -69,7 +69,7 @@ An alias to `jerryx_handler_assert_fatal`. **Summary** Expose garbage collector to scripts. If the first argument of the function -is logical true, it performs a high severity gc. Otherwise a low severity +is logical true, it performs a high pressure gc. Otherwise a low pressure gc is performed, which is also the default if no parameters passed. **Prototype** diff --git a/docs/14.EXT-REFERENCE-HANDLE-SCOPE.md b/docs/14.EXT-REFERENCE-HANDLE-SCOPE.md index 0af92702c..b79eb8ec6 100644 --- a/docs/14.EXT-REFERENCE-HANDLE-SCOPE.md +++ b/docs/14.EXT-REFERENCE-HANDLE-SCOPE.md @@ -41,7 +41,7 @@ main (void) jerry_init (JERRY_INIT_EMPTY); test_handle_scope_val (); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); jerry_cleanup (); } /* main */ @@ -93,7 +93,7 @@ main (void) jerry_init (JERRY_INIT_EMPTY); test_handle_scope_val (); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); jerry_cleanup (); } /* main */ diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index d7a980ed3..1ce685638 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -292,8 +292,14 @@ jerry_gc (jerry_gc_mode_t mode) /**< operational mode */ { jerry_assert_api_available (); - ecma_gc_run (mode == JERRY_GC_SEVERITY_LOW ? JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW - : JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH); + if (mode == JERRY_GC_PRESSURE_LOW) + { + /* Call GC directly, because 'ecma_free_unused_memory' might decide it's not yet worth it. */ + ecma_gc_run (); + return; + } + + ecma_free_unused_memory (JMEM_PRESSURE_HIGH); } /* jerry_gc */ /** diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 068458917..1e5ddc590 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -308,8 +308,6 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); - bool traverse_properties = true; - if (ecma_is_lexical_environment (object_p)) { ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p); @@ -323,7 +321,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p); - traverse_properties = false; + return; } } else @@ -492,26 +490,23 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ } } - if (traverse_properties) + ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); + + if (prop_iter_p != NULL && prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) { - ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); + prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, + prop_iter_p->next_property_cp); + } - if (prop_iter_p != NULL && prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) - { - prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, - prop_iter_p->next_property_cp); - } + while (prop_iter_p != NULL) + { + JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); - while (prop_iter_p != NULL) - { - JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); + ecma_gc_mark_property ((ecma_property_pair_t *) prop_iter_p, 0); + ecma_gc_mark_property ((ecma_property_pair_t *) prop_iter_p, 1); - ecma_gc_mark_property ((ecma_property_pair_t *) prop_iter_p, 0); - ecma_gc_mark_property ((ecma_property_pair_t *) prop_iter_p, 1); - - prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, - prop_iter_p->next_property_cp); - } + prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, + prop_iter_p->next_property_cp); } } /* ecma_gc_mark */ @@ -905,23 +900,26 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ } /* ecma_gc_free_object */ /** - * Run garbage collection + * Run garbage collection, freeing objects that are no longer referenced. */ void -ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */ +ecma_gc_run (void) { JERRY_CONTEXT (ecma_gc_new_objects) = 0; - ecma_object_t *white_gray_objects_p = JERRY_CONTEXT (ecma_gc_objects_p); - ecma_object_t *black_objects_p = NULL; + ecma_object_t white_gray_list_head; + ecma_gc_set_object_next (&white_gray_list_head, JERRY_CONTEXT (ecma_gc_objects_p)); + jmem_cpointer_t black_objects_cp = JMEM_CP_NULL; - ecma_object_t *obj_iter_p = white_gray_objects_p; - ecma_object_t *obj_prev_p = NULL; + ecma_object_t *obj_prev_p = &white_gray_list_head; + jmem_cpointer_t obj_iter_cp = obj_prev_p->gc_next_cp; + ecma_object_t *obj_iter_p; /* Move root objects (i.e. they have global or stack references) to the black list. */ - while (obj_iter_p != NULL) + while (obj_iter_cp != JMEM_CP_NULL) { - ecma_object_t *obj_next_p = ecma_gc_get_object_next (obj_iter_p); + obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp); + const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp; JERRY_ASSERT (obj_prev_p == NULL || ecma_gc_get_object_next (obj_prev_p) == obj_iter_p); @@ -929,36 +927,29 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */ if (ecma_gc_is_object_visited (obj_iter_p)) { /* Moving the object to list of marked objects. */ - if (JERRY_LIKELY (obj_prev_p != NULL)) - { - obj_prev_p->gc_next_cp = obj_iter_p->gc_next_cp; - } - else - { - white_gray_objects_p = obj_next_p; - } + obj_prev_p->gc_next_cp = obj_next_cp; - ecma_gc_set_object_next (obj_iter_p, black_objects_p); - black_objects_p = obj_iter_p; + obj_iter_p->gc_next_cp = black_objects_cp; + black_objects_cp = obj_iter_cp; } else { obj_prev_p = obj_iter_p; } - obj_iter_p = obj_next_p; + obj_iter_cp = obj_next_cp; } + ecma_object_t *first_root_object_p = JMEM_CP_GET_POINTER (ecma_object_t, black_objects_cp); + /* Mark root objects. */ - obj_iter_p = black_objects_p; + obj_iter_p = first_root_object_p; while (obj_iter_p != NULL) { ecma_gc_mark (obj_iter_p); obj_iter_p = ecma_gc_get_object_next (obj_iter_p); } - ecma_object_t *first_root_object_p = black_objects_p; - /* Mark non-root objects. */ bool marked_anything_during_current_iteration; @@ -966,12 +957,13 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */ { marked_anything_during_current_iteration = false; - obj_prev_p = NULL; - obj_iter_p = white_gray_objects_p; + obj_prev_p = &white_gray_list_head; + obj_iter_cp = obj_prev_p->gc_next_cp; - while (obj_iter_p != NULL) + while (obj_iter_cp != JMEM_CP_NULL) { - ecma_object_t *obj_next_p = ecma_gc_get_object_next (obj_iter_p); + obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp); + const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp; JERRY_ASSERT (obj_prev_p == NULL || ecma_gc_get_object_next (obj_prev_p) == obj_iter_p); @@ -979,17 +971,10 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */ if (ecma_gc_is_object_visited (obj_iter_p)) { /* Moving the object to list of marked objects */ - if (JERRY_LIKELY (obj_prev_p != NULL)) - { - obj_prev_p->gc_next_cp = obj_iter_p->gc_next_cp; - } - else - { - white_gray_objects_p = obj_next_p; - } + obj_prev_p->gc_next_cp = obj_next_cp; - ecma_gc_set_object_next (obj_iter_p, black_objects_p); - black_objects_p = obj_iter_p; + obj_iter_p->gc_next_cp = black_objects_cp; + black_objects_cp = obj_iter_cp; ecma_gc_mark (obj_iter_p); marked_anything_during_current_iteration = true; @@ -999,13 +984,13 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */ obj_prev_p = obj_iter_p; } - obj_iter_p = obj_next_p; + obj_iter_cp = obj_next_cp; } } while (marked_anything_during_current_iteration); /* Sweep objects that are currently unmarked. */ - obj_iter_p = white_gray_objects_p; + obj_iter_p = ecma_gc_get_object_next (&white_gray_list_head); while (obj_iter_p != NULL) { @@ -1018,7 +1003,8 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */ } /* Reset the reference counter of non-root black objects. */ - obj_iter_p = black_objects_p; + obj_iter_p = JMEM_CP_GET_POINTER (ecma_object_t, black_objects_cp); + JERRY_CONTEXT (ecma_gc_objects_p) = obj_iter_p; while (obj_iter_p != first_root_object_p) { @@ -1029,10 +1015,70 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */ obj_iter_p = ecma_gc_get_object_next (obj_iter_p); } - if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH) - { - obj_iter_p = black_objects_p; +#if ENABLED (JERRY_BUILTIN_REGEXP) + /* Free RegExp bytecodes stored in cache */ + re_cache_gc_run (); +#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ +} /* ecma_gc_run */ +/** + * Try to free some memory (depending on memory pressure). + * + * When called with JMEM_PRESSURE_FULL, the engine will be terminated with ERR_OUT_OF_MEMORY. + */ +void +ecma_free_unused_memory (jmem_pressure_t pressure) /**< current pressure */ +{ +#if ENABLED (JERRY_DEBUGGER) + while ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) + && JERRY_CONTEXT (debugger_byte_code_free_tail) != ECMA_NULL_POINTER) + { + /* Wait until all byte code is freed or the connection is aborted. */ + jerry_debugger_receive (NULL); + } +#endif /* ENABLED (JERRY_DEBUGGER) */ + + if (JERRY_LIKELY (pressure == JMEM_PRESSURE_LOW)) + { +#if ENABLED (JERRY_PROPRETY_HASHMAP) + if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) > ECMA_PROP_HASHMAP_ALLOC_ON) + { + --JERRY_CONTEXT (ecma_prop_hashmap_alloc_state); + } + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_PRESSURE_GC; +#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ + /* + * If there is enough newly allocated objects since last GC, probably it is worthwhile to start GC now. + * Otherwise, probability to free sufficient space is considered to be low. + */ + size_t new_objects_fraction = CONFIG_ECMA_GC_NEW_OBJECTS_FRACTION; + + if (JERRY_CONTEXT (ecma_gc_new_objects) * new_objects_fraction > JERRY_CONTEXT (ecma_gc_objects_number)) + { + ecma_gc_run (); + } + + return; + } + else if (pressure == JMEM_PRESSURE_HIGH) + { + /* Freeing as much memory as we currently can */ +#if ENABLED (JERRY_PROPRETY_HASHMAP) + if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_HIGH_PRESSURE_GC) + { + JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_MAX; + } + else if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) < ECMA_PROP_HASHMAP_ALLOC_MAX) + { + ++JERRY_CONTEXT (ecma_prop_hashmap_alloc_state); + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_HIGH_PRESSURE_GC; + } +#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ + + ecma_gc_run (); + + /* Free hashmaps of remaining objects. */ + ecma_object_t *obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_p); while (obj_iter_p != NULL) { if (!ecma_is_lexical_environment (obj_iter_p) @@ -1048,70 +1094,18 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */ obj_iter_p = ecma_gc_get_object_next (obj_iter_p); } + + jmem_pools_collect_empty (); + return; } - - JERRY_CONTEXT (ecma_gc_objects_p) = black_objects_p; - -#if ENABLED (JERRY_BUILTIN_REGEXP) - /* Free RegExp bytecodes stored in cache */ - re_cache_gc_run (); -#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ -} /* ecma_gc_run */ - -/** - * Try to free some memory (depending on severity). - */ -void -ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< severity of the request */ -{ -#if ENABLED (JERRY_DEBUGGER) - while ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) - && JERRY_CONTEXT (debugger_byte_code_free_tail) != ECMA_NULL_POINTER) + else if (JERRY_UNLIKELY (pressure == JMEM_PRESSURE_FULL)) { - /* Wait until all byte code is freed or the connection is aborted. */ - jerry_debugger_receive (NULL); - } -#endif /* ENABLED (JERRY_DEBUGGER) */ - - if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW) - { -#if ENABLED (JERRY_PROPRETY_HASHMAP) - if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) > ECMA_PROP_HASHMAP_ALLOC_ON) - { - --JERRY_CONTEXT (ecma_prop_hashmap_alloc_state); - } - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_SEV_GC; -#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ - - /* - * If there is enough newly allocated objects since last GC, probably it is worthwhile to start GC now. - * Otherwise, probability to free sufficient space is considered to be low. - */ - size_t new_objects_share = CONFIG_ECMA_GC_NEW_OBJECTS_SHARE_TO_START_GC; - - if (JERRY_CONTEXT (ecma_gc_new_objects) * new_objects_share > JERRY_CONTEXT (ecma_gc_objects_number)) - { - ecma_gc_run (severity); - } + jerry_fatal (ERR_OUT_OF_MEMORY); } else { - JERRY_ASSERT (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH); - -#if ENABLED (JERRY_PROPRETY_HASHMAP) - if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_HIGH_SEV_GC) - { - JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_MAX; - } - else if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) < ECMA_PROP_HASHMAP_ALLOC_MAX) - { - ++JERRY_CONTEXT (ecma_prop_hashmap_alloc_state); - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_HIGH_SEV_GC; - } -#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ - - /* Freeing as much memory as we currently can */ - ecma_gc_run (severity); + JERRY_ASSERT (pressure == JMEM_PRESSURE_NONE); + JERRY_UNREACHABLE (); } } /* ecma_free_unused_memory */ diff --git a/jerry-core/ecma/base/ecma-gc.h b/jerry-core/ecma/base/ecma-gc.h index f50c88864..6a4166adb 100644 --- a/jerry-core/ecma/base/ecma-gc.h +++ b/jerry-core/ecma/base/ecma-gc.h @@ -29,8 +29,8 @@ void ecma_init_gc_info (ecma_object_t *object_p); void ecma_ref_object (ecma_object_t *object_p); void ecma_deref_object (ecma_object_t *object_p); -void ecma_gc_run (jmem_free_unused_memory_severity_t severity); -void ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity); +void ecma_gc_run (void); +void ecma_free_unused_memory (jmem_pressure_t pressure); /** * @} diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 5f4f78155..470c9e139 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -59,7 +59,7 @@ typedef enum ECMA_STATUS_API_AVAILABLE = (1u << 0), /**< api available */ ECMA_STATUS_DIRECT_EVAL = (1u << 1), /**< eval is called directly */ #if ENABLED (JERRY_PROPRETY_HASHMAP) - ECMA_STATUS_HIGH_SEV_GC = (1u << 2), /**< last gc run was a high severity run */ + ECMA_STATUS_HIGH_PRESSURE_GC = (1u << 2), /**< last gc was under high pressure */ #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ ECMA_STATUS_EXCEPTION = (1u << 3), /**< last exception is a normal exception */ } ecma_status_flag_t; diff --git a/jerry-core/ecma/base/ecma-init-finalize.c b/jerry-core/ecma/base/ecma-init-finalize.c index 040456087..9e2374747 100644 --- a/jerry-core/ecma/base/ecma-init-finalize.c +++ b/jerry-core/ecma/base/ecma-init-finalize.c @@ -37,11 +37,9 @@ ecma_init (void) { ecma_init_global_lex_env (); - jmem_register_free_unused_memory_callback (ecma_free_unused_memory); - #if ENABLED (JERRY_PROPRETY_HASHMAP) JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_ON; - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_SEV_GC; + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_PRESSURE_GC; #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ #if defined (JERRY_CALL_STACK_LIMIT) && (JERRY_CALL_STACK_LIMIT != 0) @@ -59,10 +57,9 @@ ecma_init (void) void ecma_finalize (void) { - jmem_unregister_free_unused_memory_callback (ecma_free_unused_memory); ecma_finalize_global_lex_env (); ecma_finalize_builtins (); - ecma_gc_run (JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW); + ecma_gc_run (); ecma_finalize_lit_storage (); } /* ecma_finalize */ diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 60805eee3..49bd3deb9 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -111,10 +111,10 @@ typedef enum */ typedef enum { - JERRY_GC_SEVERITY_LOW, /**< free unused objects, but keep memory + JERRY_GC_PRESSURE_LOW, /**< free unused objects, but keep memory * allocated for performance improvements * such as property hash tables for large objects */ - JERRY_GC_SEVERITY_HIGH /**< free as much memory as possible */ + JERRY_GC_PRESSURE_HIGH /**< free as much memory as possible */ } jerry_gc_mode_t; /** diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 733342794..e339b5194 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -53,13 +53,13 @@ #define CONFIG_MEM_HEAP_DESIRED_LIMIT (JERRY_MIN (CONFIG_MEM_HEAP_SIZE / 32, CONFIG_MEM_HEAP_MAX_LIMIT)) /** - * Share of newly allocated since last GC objects among all currently allocated objects, - * after achieving which, GC is started upon low severity try-give-memory-back requests. + * Amount of newly allocated objects since the last GC run, represented as a fraction of all allocated objects, + * which when reached will trigger garbage collection to run with a low pressure setting. * - * Share is calculated as the following: - * 1.0 / CONFIG_ECMA_GC_NEW_OBJECTS_SHARE_TO_START_GC + * The fraction is calculated as: + * 1.0 / CONFIG_ECMA_GC_NEW_OBJECTS_FRACTION */ -#define CONFIG_ECMA_GC_NEW_OBJECTS_SHARE_TO_START_GC (16) +#define CONFIG_ECMA_GC_NEW_OBJECTS_FRACTION (16) #if !ENABLED (JERRY_SYSTEM_ALLOCATOR) /** @@ -121,7 +121,6 @@ struct jerry_context_t #if ENABLED (JERRY_CPOINTER_32_BIT) jmem_pools_chunk_t *jmem_free_16_byte_chunk_p; /**< list of free sixteen byte pool chunks */ #endif /* ENABLED (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 * const *lit_magic_string_ex_array; /**< array of external magic strings */ const lit_utf8_size_t *lit_magic_string_ex_sizes; /**< external magic string lengths */ ecma_lit_storage_item_t *string_list_first_p; /**< first item of the literal string list */ diff --git a/jerry-core/jmem/jmem-allocator-internal.h b/jerry-core/jmem/jmem-allocator-internal.h index ccf057670..27b9d003e 100644 --- a/jerry-core/jmem/jmem-allocator-internal.h +++ b/jerry-core/jmem/jmem-allocator-internal.h @@ -45,16 +45,11 @@ #endif /* ENABLED (JERRY_VALGRIND) */ /** @} */ -#if ENABLED (JERRY_MEM_STATS) -void jmem_heap_stats_reset_peak (void); -void jmem_heap_stats_print (void); -#endif /* ENABLED (JERRY_MEM_STATS) */ - void jmem_heap_init (void); void jmem_heap_finalize (void); bool jmem_is_heap_pointer (const void *pointer); - -void jmem_run_free_unused_memory_callbacks (jmem_free_unused_memory_severity_t severity); +void *jmem_heap_alloc_block_internal (const size_t size); +void jmem_heap_free_block_internal (void *ptr, const size_t size); /** * \addtogroup poolman Memory pool manager @@ -62,11 +57,30 @@ void jmem_run_free_unused_memory_callbacks (jmem_free_unused_memory_severity_t s */ void jmem_pools_finalize (void); -void jmem_pools_collect_empty (void); /** * @} * @} */ +/** + * @{ + * Jerry mem-stat definitions + */ +#if ENABLED (JERRY_MEM_STATS) +void jmem_heap_stat_init (void); +void jmem_heap_stat_alloc (size_t num); +void jmem_heap_stat_free (size_t num); + +#define JMEM_HEAP_STAT_INIT() jmem_heap_stat_init () +#define JMEM_HEAP_STAT_ALLOC(v1) jmem_heap_stat_alloc (v1) +#define JMEM_HEAP_STAT_FREE(v1) jmem_heap_stat_free (v1) +#else /* !ENABLED (JERRY_MEM_STATS) */ +#define JMEM_HEAP_STAT_INIT() +#define JMEM_HEAP_STAT_ALLOC(v1) JERRY_UNUSED (v1) +#define JMEM_HEAP_STAT_FREE(v1) JERRY_UNUSED (v1) +#endif /* ENABLED (JERRY_MEM_STATS) */ + +/** @} */ + #endif /* !JMEM_ALLOCATOR_INTERNAL_H */ diff --git a/jerry-core/jmem/jmem-allocator.c b/jerry-core/jmem/jmem-allocator.c index e887680e7..e59148031 100644 --- a/jerry-core/jmem/jmem-allocator.c +++ b/jerry-core/jmem/jmem-allocator.c @@ -232,40 +232,3 @@ jmem_decompress_pointer (uintptr_t compressed_pointer) /**< pointer to decompres return (void *) uint_ptr; } /* jmem_decompress_pointer */ -/** - * Register specified 'try to give memory back' callback routine - */ -void -jmem_register_free_unused_memory_callback (jmem_free_unused_memory_callback_t callback) /**< callback routine */ -{ - /* Currently only one callback is supported */ - JERRY_ASSERT (JERRY_CONTEXT (jmem_free_unused_memory_callback) == NULL); - - JERRY_CONTEXT (jmem_free_unused_memory_callback) = callback; -} /* jmem_register_free_unused_memory_callback */ - -/** - * Unregister specified 'try to give memory back' callback routine - */ -void -jmem_unregister_free_unused_memory_callback (jmem_free_unused_memory_callback_t callback) /**< callback routine */ -{ - /* Currently only one callback is supported */ - JERRY_ASSERT (JERRY_CONTEXT (jmem_free_unused_memory_callback) == callback); - - JERRY_CONTEXT (jmem_free_unused_memory_callback) = NULL; -} /* jmem_unregister_free_unused_memory_callback */ - -/** - * Run 'try to give memory back' callbacks with specified severity - */ -void -jmem_run_free_unused_memory_callbacks (jmem_free_unused_memory_severity_t severity) /**< severity of the request */ -{ - if (JERRY_CONTEXT (jmem_free_unused_memory_callback) != NULL) - { - JERRY_CONTEXT (jmem_free_unused_memory_callback) (severity); - } - - jmem_pools_collect_empty (); -} /* jmem_run_free_unused_memory_callbacks */ diff --git a/jerry-core/jmem/jmem-heap.c b/jerry-core/jmem/jmem-heap.c index a5b00fecb..7073ce2fd 100644 --- a/jerry-core/jmem/jmem-heap.c +++ b/jerry-core/jmem/jmem-heap.c @@ -17,6 +17,7 @@ * Heap implementation */ +#include "ecma-gc.h" #include "jcontext.h" #include "jmem.h" #include "jrt-bit-fields.h" @@ -65,44 +66,6 @@ jmem_heap_get_region_end (jmem_heap_free_t *curr_p) /**< current region */ } /* jmem_heap_get_region_end */ #endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */ -/** - * @{ - * JMEM_HEAP_STAT_xxx definitions - */ -#if ENABLED (JERRY_MEM_STATS) -static void jmem_heap_stat_init (void); -static void jmem_heap_stat_alloc (size_t num); -static void jmem_heap_stat_free (size_t num); - -#define JMEM_HEAP_STAT_INIT() jmem_heap_stat_init () -#define JMEM_HEAP_STAT_ALLOC(v1) jmem_heap_stat_alloc (v1) -#define JMEM_HEAP_STAT_FREE(v1) jmem_heap_stat_free (v1) - -#if !ENABLED (JERRY_SYSTEM_ALLOCATOR) -static void jmem_heap_stat_skip (void); -static void jmem_heap_stat_nonskip (void); -static void jmem_heap_stat_alloc_iter (void); -static void jmem_heap_stat_free_iter (void); - -#define JMEM_HEAP_STAT_SKIP() jmem_heap_stat_skip () -#define JMEM_HEAP_STAT_NONSKIP() jmem_heap_stat_nonskip () -#define JMEM_HEAP_STAT_ALLOC_ITER() jmem_heap_stat_alloc_iter () -#define JMEM_HEAP_STAT_FREE_ITER() jmem_heap_stat_free_iter () -#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */ -#else /* !ENABLED (JERRY_MEM_STATS) */ -#define JMEM_HEAP_STAT_INIT() -#define JMEM_HEAP_STAT_ALLOC(v1) JERRY_UNUSED (v1) -#define JMEM_HEAP_STAT_FREE(v1) JERRY_UNUSED (v1) - -#if !ENABLED (JERRY_SYSTEM_ALLOCATOR) -#define JMEM_HEAP_STAT_SKIP() -#define JMEM_HEAP_STAT_NONSKIP() -#define JMEM_HEAP_STAT_ALLOC_ITER() -#define JMEM_HEAP_STAT_FREE_ITER() -#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */ -#endif /* ENABLED (JERRY_MEM_STATS) */ -/** @} */ - /** * Startup initialization of heap */ @@ -156,7 +119,7 @@ jmem_heap_finalize (void) * NULL - if there is not enough memory. */ static void * JERRY_ATTR_HOT -jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block */ +jmem_heap_alloc (const size_t size) /**< size of requested block */ { #if !ENABLED (JERRY_SYSTEM_ALLOCATOR) /* Align size. */ @@ -174,7 +137,11 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block JMEM_VALGRIND_DEFINED_SPACE (data_space_p, sizeof (jmem_heap_free_t)); JERRY_CONTEXT (jmem_heap_allocated_size) += JMEM_ALIGNMENT; - JMEM_HEAP_STAT_ALLOC_ITER (); + + if (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit)) + { + JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT; + } if (data_space_p->size == JMEM_ALIGNMENT) { @@ -208,12 +175,11 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block uint32_t current_offset = JERRY_HEAP_CONTEXT (first).next_offset; jmem_heap_free_t *prev_p = &JERRY_HEAP_CONTEXT (first); - while (current_offset != JMEM_HEAP_END_OF_LIST) + while (JERRY_LIKELY (current_offset != JMEM_HEAP_END_OF_LIST)) { jmem_heap_free_t *current_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (current_offset); JERRY_ASSERT (jmem_is_heap_pointer (current_p)); JMEM_VALGRIND_DEFINED_SPACE (current_p, sizeof (jmem_heap_free_t)); - JMEM_HEAP_STAT_ALLOC_ITER (); const uint32_t next_offset = current_p->next_offset; JERRY_ASSERT (next_offset == JMEM_HEAP_END_OF_LIST @@ -223,7 +189,6 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block { /* Region is sufficiently big, store address. */ data_space_p = current_p; - JERRY_CONTEXT (jmem_heap_allocated_size) += required_size; /* Region was larger than necessary. */ if (current_p->size > required_size) @@ -254,6 +219,13 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block JERRY_CONTEXT (jmem_heap_list_skip_p) = prev_p; /* Found enough space. */ + JERRY_CONTEXT (jmem_heap_allocated_size) += required_size; + + while (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit)) + { + JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT; + } + break; } @@ -264,25 +236,18 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block } } - while (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit)) - { - JERRY_CONTEXT (jmem_heap_limit) += CONFIG_MEM_HEAP_DESIRED_LIMIT; - } - JMEM_VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t)); - if (JERRY_UNLIKELY (!data_space_p)) - { - return NULL; - } - JERRY_ASSERT ((uintptr_t) data_space_p % JMEM_ALIGNMENT == 0); - JMEM_VALGRIND_UNDEFINED_SPACE (data_space_p, size); - JMEM_HEAP_STAT_ALLOC (size); +#if ENABLED (JERRY_VALGRIND) + if (data_space_p != NULL) + { + JMEM_VALGRIND_UNDEFINED_SPACE (data_space_p, size); + } +#endif /* ENABLED (JERRY_VALGRIND) */ return (void *) data_space_p; #else /* ENABLED (JERRY_SYSTEM_ALLOCATOR) */ - JMEM_HEAP_STAT_ALLOC (size); JERRY_CONTEXT (jmem_heap_allocated_size) += size; while (JERRY_CONTEXT (jmem_heap_allocated_size) >= JERRY_CONTEXT (jmem_heap_limit)) @@ -292,92 +257,82 @@ jmem_heap_alloc_block_internal (const size_t size) /**< size of requested block return malloc (size); #endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */ -} /* jmem_heap_alloc_block_internal */ +} /* jmem_heap_alloc */ /** - * Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory. + * Allocation of memory block, reclaiming memory if the request cannot be fulfilled. * * Note: - * 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 + * Each failed allocation attempt tries to reclaim memory with an increasing pressure, + * up to 'max_pressure', or until a sufficient memory block is found. When JMEM_PRESSURE_FULL + * is reached, the engine is terminated with ERR_OUT_OF_MEMORY. The `max_pressure` argument + * can be used to limit the maximum pressure, and prevent the engine from terminating. * - * @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 + * @return NULL, if the required memory size is 0 or not enough memory + * pointer to the allocated memory block, if allocation is successful */ 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 */ +jmem_heap_gc_and_alloc_block (const size_t size, /**< required memory size */ + jmem_pressure_t max_pressure) /**< pressure limit */ { if (JERRY_UNLIKELY (size == 0)) { return NULL; } -#if ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) - jmem_run_free_unused_memory_callbacks (JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH); -#endif /* ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */ + jmem_pressure_t pressure = JMEM_PRESSURE_NONE; +#if !ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) if (JERRY_CONTEXT (jmem_heap_allocated_size) + size >= JERRY_CONTEXT (jmem_heap_limit)) +#endif /* !ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */ { - jmem_run_free_unused_memory_callbacks (JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW); + pressure = JMEM_PRESSURE_LOW; + ecma_free_unused_memory (pressure); } - void *data_space_p = jmem_heap_alloc_block_internal (size); + void *data_space_p = jmem_heap_alloc (size); - if (JERRY_LIKELY (data_space_p != NULL)) + while (JERRY_UNLIKELY (data_space_p == NULL) && JERRY_LIKELY (pressure < max_pressure)) { - JMEM_VALGRIND_MALLOCLIKE_SPACE (data_space_p, size); - return data_space_p; - } - - for (jmem_free_unused_memory_severity_t severity = JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW; - severity <= JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH; - severity = (jmem_free_unused_memory_severity_t) (severity + 1)) - { - jmem_run_free_unused_memory_callbacks (severity); - - data_space_p = jmem_heap_alloc_block_internal (size); - - if (JERRY_LIKELY (data_space_p != NULL)) - { - JMEM_VALGRIND_MALLOCLIKE_SPACE (data_space_p, size); - return data_space_p; - } - } - - JERRY_ASSERT (data_space_p == NULL); - - if (!ret_null_on_error) - { - jerry_fatal (ERR_OUT_OF_MEMORY); + pressure++; + ecma_free_unused_memory (pressure); + data_space_p = jmem_heap_alloc (size); } 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. + * Internal method for allocating a memory block. + */ +inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE +jmem_heap_alloc_block_internal (const size_t size) /**< required memory size */ +{ + return jmem_heap_gc_and_alloc_block (size, JMEM_PRESSURE_FULL); +} /* jmem_heap_alloc_block_internal */ + +/** + * Allocation of memory block, reclaiming unused memory if there is not enough. * * Note: - * If there is still not enough memory after running the callbacks, then the engine will be - * terminated with ERR_OUT_OF_MEMORY. + * If a sufficiently sized block can't be found, the engine will be terminated with ERR_OUT_OF_MEMORY. * * @return NULL, if the required memory is 0 * pointer to allocated memory block, otherwise */ inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE -jmem_heap_alloc_block (const size_t size) /**< required memory size */ +jmem_heap_alloc_block (const size_t size) /**< required memory size */ { - return jmem_heap_gc_and_alloc_block (size, false); + void *block_p = jmem_heap_gc_and_alloc_block (size, JMEM_PRESSURE_FULL); + JMEM_HEAP_STAT_ALLOC (size); + return block_p; } /* jmem_heap_alloc_block */ /** - * Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory. + * Allocation of memory block, reclaiming unused memory if there is not enough. * * Note: - * If there is still not enough memory after running the callbacks, NULL will be returned. + * If a sufficiently sized block can't be found, NULL will be returned. * * @return NULL, if the required memory size is 0 * also NULL, if the allocation has failed @@ -386,15 +341,24 @@ jmem_heap_alloc_block (const size_t size) /**< required memory size */ inline void * JERRY_ATTR_HOT JERRY_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); + void *block_p = jmem_heap_gc_and_alloc_block (size, JMEM_PRESSURE_HIGH); + +#if ENABLED (JERRY_MEM_STATS) + if (block_p != NULL) + { + JMEM_HEAP_STAT_ALLOC (size); + } +#endif /* ENABLED (JERRY_MEM_STATS) */ + + return block_p; } /* jmem_heap_alloc_block_null_on_error */ /** - * Free the memory block. + * Internal method for freeing a memory block. */ void JERRY_ATTR_HOT -jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the block */ - const size_t size) /**< size of allocated region */ +jmem_heap_free_block_internal (void *ptr, /**< pointer to beginning of data space of the block */ + const size_t size) /**< size of allocated region */ { #if !ENABLED (JERRY_SYSTEM_ALLOCATOR) /* checking that ptr points to the heap */ @@ -404,7 +368,6 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the JMEM_VALGRIND_FREELIKE_SPACE (ptr); JMEM_VALGRIND_NOACCESS_SPACE (ptr, size); - JMEM_HEAP_STAT_FREE_ITER (); jmem_heap_free_t *block_p = (jmem_heap_free_t *) ptr; jmem_heap_free_t *prev_p; @@ -415,12 +378,10 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the if (block_p > JERRY_CONTEXT (jmem_heap_list_skip_p)) { prev_p = JERRY_CONTEXT (jmem_heap_list_skip_p); - JMEM_HEAP_STAT_SKIP (); } else { prev_p = &JERRY_HEAP_CONTEXT (first); - JMEM_HEAP_STAT_NONSKIP (); } JERRY_ASSERT (jmem_is_heap_pointer (block_p)); @@ -436,8 +397,6 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the JMEM_VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t)); JMEM_VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t)); prev_p = next_p; - - JMEM_HEAP_STAT_FREE_ITER (); } next_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (prev_p->next_offset); @@ -491,9 +450,7 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the JMEM_VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_free_t)); JERRY_ASSERT (JERRY_CONTEXT (jmem_heap_limit) >= JERRY_CONTEXT (jmem_heap_allocated_size)); - JMEM_HEAP_STAT_FREE (size); #else /* ENABLED (JERRY_SYSTEM_ALLOCATOR) */ - JMEM_HEAP_STAT_FREE (size); JERRY_CONTEXT (jmem_heap_allocated_size) -= size; while (JERRY_CONTEXT (jmem_heap_allocated_size) + CONFIG_MEM_HEAP_DESIRED_LIMIT <= JERRY_CONTEXT (jmem_heap_limit)) @@ -503,6 +460,18 @@ jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the free (ptr); #endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */ +} /* jmem_heap_free_block_internal */ + +/** + * Free memory block + */ +inline void JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE +jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the block */ + const size_t size) /**< size of allocated region */ +{ + jmem_heap_free_block_internal (ptr, size); + JMEM_HEAP_STAT_FREE (size); + return; } /* jmem_heap_free_block */ #ifndef JERRY_NDEBUG @@ -577,23 +546,12 @@ jmem_heap_stats_print (void) heap_stats->peak_object_bytes, heap_stats->property_bytes, heap_stats->peak_property_bytes); -#if !ENABLED (JERRY_SYSTEM_ALLOCATOR) - JERRY_DEBUG_MSG (" Skip-ahead ratio = %zu.%04zu\n" - " Average alloc iteration = %zu.%04zu\n" - " Average free iteration = %zu.%04zu\n", - heap_stats->skip_count / heap_stats->nonskip_count, - heap_stats->skip_count % heap_stats->nonskip_count * 10000 / heap_stats->nonskip_count, - heap_stats->alloc_iter_count / heap_stats->alloc_count, - heap_stats->alloc_iter_count % heap_stats->alloc_count * 10000 / heap_stats->alloc_count, - heap_stats->free_iter_count / heap_stats->free_count, - heap_stats->free_iter_count % heap_stats->free_count * 10000 / heap_stats->free_count); -#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */ } /* jmem_heap_stats_print */ /** * Initalize heap memory usage statistics account structure */ -static void +void jmem_heap_stat_init (void) { #if !ENABLED (JERRY_SYSTEM_ALLOCATOR) @@ -604,7 +562,7 @@ jmem_heap_stat_init (void) /** * Account allocation */ -static void +void jmem_heap_stat_alloc (size_t size) /**< Size of allocated block */ { const size_t aligned_size = (size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT * JMEM_ALIGNMENT; @@ -614,7 +572,6 @@ jmem_heap_stat_alloc (size_t size) /**< Size of allocated block */ heap_stats->allocated_bytes += aligned_size; heap_stats->waste_bytes += waste_bytes; - heap_stats->alloc_count++; if (heap_stats->allocated_bytes > heap_stats->peak_allocated_bytes) { @@ -630,7 +587,7 @@ jmem_heap_stat_alloc (size_t size) /**< Size of allocated block */ /** * Account freeing */ -static void +void jmem_heap_stat_free (size_t size) /**< Size of freed block */ { const size_t aligned_size = (size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT * JMEM_ALIGNMENT; @@ -638,48 +595,10 @@ jmem_heap_stat_free (size_t size) /**< Size of freed block */ jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats); - heap_stats->free_count++; heap_stats->allocated_bytes -= aligned_size; heap_stats->waste_bytes -= waste_bytes; } /* jmem_heap_stat_free */ -#if !ENABLED (JERRY_SYSTEM_ALLOCATOR) -/** - * Counts number of skip-aheads during insertion of free block - */ -static void -jmem_heap_stat_skip (void) -{ - JERRY_CONTEXT (jmem_heap_stats).skip_count++; -} /* jmem_heap_stat_skip */ - -/** - * Counts number of times we could not skip ahead during free block insertion - */ -static void -jmem_heap_stat_nonskip (void) -{ - JERRY_CONTEXT (jmem_heap_stats).nonskip_count++; -} /* jmem_heap_stat_nonskip */ - -/** - * Count number of iterations required for allocations - */ -static void -jmem_heap_stat_alloc_iter (void) -{ - JERRY_CONTEXT (jmem_heap_stats).alloc_iter_count++; -} /* jmem_heap_stat_alloc_iter */ - -/** - * Counts number of iterations required for inserting free blocks - */ -static void -jmem_heap_stat_free_iter (void) -{ - JERRY_CONTEXT (jmem_heap_stats).free_iter_count++; -} /* jmem_heap_stat_free_iter */ -#endif /* !ENABLED (JERRY_SYSTEM_ALLOCATOR) */ #endif /* ENABLED (JERRY_MEM_STATS) */ /** diff --git a/jerry-core/jmem/jmem-poolman.c b/jerry-core/jmem/jmem-poolman.c index ebe3f711d..fcec5b46d 100644 --- a/jerry-core/jmem/jmem-poolman.c +++ b/jerry-core/jmem/jmem-poolman.c @@ -24,6 +24,10 @@ #define JMEM_ALLOCATOR_INTERNAL #include "jmem-allocator-internal.h" +#if ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) +#include "ecma-gc.h" +#endif /* ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */ + /** \addtogroup mem Memory allocation * @{ * @@ -55,7 +59,7 @@ inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE jmem_pools_alloc (size_t size) /**< size of the chunk */ { #if ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) - jmem_run_free_unused_memory_callbacks (JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH); + ecma_free_unused_memory (JMEM_PRESSURE_LOW); #endif /* ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */ #if ENABLED (JERRY_CPOINTER_32_BIT) @@ -70,16 +74,17 @@ jmem_pools_alloc (size_t size) /**< size of the chunk */ const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_8_byte_chunk_p); JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); - JERRY_CONTEXT (jmem_free_8_byte_chunk_p) = chunk_p->next_p; - JMEM_VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); + JMEM_HEAP_STAT_ALLOC (8); return (void *) chunk_p; } else { - return (void *) jmem_heap_alloc_block (8); + void *chunk_p = jmem_heap_alloc_block_internal (8); + JMEM_HEAP_STAT_ALLOC (8); + return chunk_p; } #if ENABLED (JERRY_CPOINTER_32_BIT) @@ -92,16 +97,17 @@ jmem_pools_alloc (size_t size) /**< size of the chunk */ const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_16_byte_chunk_p); JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); - JERRY_CONTEXT (jmem_free_16_byte_chunk_p) = chunk_p->next_p; - JMEM_VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); + JMEM_HEAP_STAT_ALLOC (16); return (void *) chunk_p; } else { - return (void *) jmem_heap_alloc_block (16); + void *chunk_p = jmem_heap_alloc_block_internal (16); + JMEM_HEAP_STAT_ALLOC (16); + return chunk_p; } #endif /* ENABLED (JERRY_CPOINTER_32_BIT) */ } /* jmem_pools_alloc */ @@ -114,6 +120,7 @@ jmem_pools_free (void *chunk_p, /**< pointer to the chunk */ size_t size) /**< size of the chunk */ { JERRY_ASSERT (chunk_p != NULL); + JMEM_HEAP_STAT_FREE (size); jmem_pools_chunk_t *const chunk_to_free_p = (jmem_pools_chunk_t *) chunk_p; @@ -158,7 +165,7 @@ jmem_pools_collect_empty (void) jmem_pools_chunk_t *const next_p = chunk_p->next_p; JMEM_VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); - jmem_heap_free_block (chunk_p, 8); + jmem_heap_free_block_internal (chunk_p, 8); chunk_p = next_p; } @@ -172,7 +179,7 @@ jmem_pools_collect_empty (void) jmem_pools_chunk_t *const next_p = chunk_p->next_p; JMEM_VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t)); - jmem_heap_free_block (chunk_p, 16); + jmem_heap_free_block_internal (chunk_p, 16); chunk_p = next_p; } #endif /* ENABLED (JERRY_CPOINTER_32_BIT) */ diff --git a/jerry-core/jmem/jmem.h b/jerry-core/jmem/jmem.h index ff5d8c659..083bf11e9 100644 --- a/jerry-core/jmem/jmem.h +++ b/jerry-core/jmem/jmem.h @@ -70,19 +70,21 @@ typedef uint16_t jmem_cpointer_t; #endif /* ENABLED (JERRY_CPOINTER_32_BIT) */ /** - * Severity of a 'try give memory back' request + * Memory usage pressure for reclaiming unused memory. * - * The request are posted sequentially beginning from - * low to high until enough memory is freed. + * Each failed allocation will try to reclaim memory with increasing pressure, + * until enough memory is freed to fulfill the allocation request. * - * If not enough memory is freed upon a high request + * If not enough memory is freed and JMEM_PRESSURE_FULL is reached, * then the engine is shut down with ERR_OUT_OF_MEMORY. */ typedef enum { - JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW, /**< 'low' severity */ - JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH, /**< 'high' severity */ -} jmem_free_unused_memory_severity_t; + JMEM_PRESSURE_NONE, /**< no memory pressure */ + JMEM_PRESSURE_LOW, /**< low memory pressure */ + JMEM_PRESSURE_HIGH, /**< high memory pressure */ + JMEM_PRESSURE_FULL, /**< memory full */ +} jmem_pressure_t; /** * Node for free chunk list @@ -133,15 +135,6 @@ typedef struct size_t property_bytes; /**< allocated memory for properties */ size_t peak_property_bytes; /**< peak allocated memory for properties */ - - size_t skip_count; /**< Number of skip-aheads during insertion of free block */ - size_t nonskip_count; /**< Number of times we could not skip ahead during - * free block insertion */ - - size_t alloc_count; /**< number of memory allocations */ - size_t free_count; /**< number of memory frees */ - size_t alloc_iter_count; /**< Number of iterations required for allocations */ - size_t free_iter_count; /**< Number of iterations required for inserting free blocks */ } jmem_heap_stats_t; void jmem_stats_allocate_byte_code_bytes (size_t property_size); @@ -154,21 +147,13 @@ void jmem_stats_allocate_property_bytes (size_t property_size); void jmem_stats_free_property_bytes (size_t property_size); void jmem_heap_get_stats (jmem_heap_stats_t *); +void jmem_heap_stats_reset_peak (void); +void jmem_heap_stats_print (void); #endif /* ENABLED (JERRY_MEM_STATS) */ jmem_cpointer_t JERRY_ATTR_PURE jmem_compress_pointer (const void *pointer_p); void * JERRY_ATTR_PURE jmem_decompress_pointer (uintptr_t compressed_pointer); -/** - * A free memory callback routine type. - */ -typedef void (*jmem_free_unused_memory_callback_t) (jmem_free_unused_memory_severity_t); - -void jmem_register_free_unused_memory_callback (jmem_free_unused_memory_callback_t callback); -void jmem_unregister_free_unused_memory_callback (jmem_free_unused_memory_callback_t callback); - -void jmem_run_free_unused_memory_callbacks (jmem_free_unused_memory_severity_t severity); - /** * Define a local array variable and allocate memory for the array on the heap. * @@ -245,6 +230,7 @@ void jmem_run_free_unused_memory_callbacks (jmem_free_unused_memory_severity_t s void *jmem_pools_alloc (size_t size); void jmem_pools_free (void *chunk_p, size_t size); +void jmem_pools_collect_empty (void); /** * @} diff --git a/jerry-ext/handler/handler-gc.c b/jerry-ext/handler/handler-gc.c index 5f669b018..cca681711 100644 --- a/jerry-ext/handler/handler-gc.c +++ b/jerry-ext/handler/handler-gc.c @@ -29,8 +29,8 @@ jerryx_handler_gc (const jerry_value_t func_obj_val, /**< function object */ (void) func_obj_val; /* unused */ (void) this_p; /* unused */ - jerry_gc_mode_t mode = ((args_cnt > 0 && jerry_value_to_boolean (args_p[0])) ? JERRY_GC_SEVERITY_HIGH - : JERRY_GC_SEVERITY_LOW); + jerry_gc_mode_t mode = ((args_cnt > 0 && jerry_value_to_boolean (args_p[0])) ? JERRY_GC_PRESSURE_HIGH + : JERRY_GC_PRESSURE_LOW); jerry_gc (mode); return jerry_create_undefined (); diff --git a/tests/unit-core/test-api.c b/tests/unit-core/test-api.c index ad6ef636f..5a89f1132 100644 --- a/tests/unit-core/test-api.c +++ b/tests/unit-core/test-api.c @@ -727,7 +727,7 @@ main (void) jerry_release_value (global_obj_val); /* Test: run gc. */ - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); /* Test: spaces */ const jerry_char_t eval_code_src2[] = "\x0a \x0b \x0c \xc2\xa0 \xe2\x80\xa8 \xe2\x80\xa9 \xef\xbb\xbf 4321"; diff --git a/tests/unit-core/test-heap.c b/tests/unit-core/test-heap.c deleted file mode 100644 index 85b37bffb..000000000 --- a/tests/unit-core/test-heap.c +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include "jmem.h" - -#define JMEM_ALLOCATOR_INTERNAL -#include "jmem-allocator-internal.h" - -#include "test-common.h" - -/* Heap size is 32K. */ -#define test_heap_size (32 * 1024) - -/* Iterations count. */ -#define test_iters (4 * 1024) - -/* Subiterations count. */ -#define test_sub_iters 32 - -/* Threshold size of block to allocate. */ -#define test_threshold_block_size 8192 - -uint8_t *ptrs[test_sub_iters]; -size_t sizes[test_sub_iters]; -bool is_one_chunked[test_sub_iters]; - -static void -test_heap_give_some_memory_back (jmem_free_unused_memory_severity_t severity) -{ - int p; - - if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW) - { - p = 8; - } - else - { - TEST_ASSERT (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH); - - p = 1; - } - - for (int i = 0; i < test_sub_iters; i++) - { - if (rand () % p == 0) - { - if (ptrs[i] != NULL) - { - for (size_t k = 0; k < sizes[i]; k++) - { - TEST_ASSERT (ptrs[i][k] == 0); - } - - jmem_heap_free_block (ptrs[i], sizes[i]); - ptrs[i] = NULL; - } - } - } -} /* test_heap_give_some_memory_back */ - -int -main (void) -{ - TEST_INIT (); - - jmem_heap_init (); - - jmem_register_free_unused_memory_callback (test_heap_give_some_memory_back); - -#ifdef JMEM_STATS - // TODO: uncomment it after we solve the divide zero issue. - // jmem_heap_stats_print (); -#endif /* JMEM_STATS */ - - for (uint32_t i = 0; i < test_iters; i++) - { - for (uint32_t j = 0; j < test_sub_iters; j++) - { - size_t size = (size_t) rand () % test_threshold_block_size; - ptrs[j] = (uint8_t *) jmem_heap_alloc_block (size); - sizes[j] = size; - - TEST_ASSERT (sizes[j] == 0 || ptrs[j] != NULL); - memset (ptrs[j], 0, sizes[j]); - } - - /* jmem_heap_print (true); */ - - for (uint32_t j = 0; j < test_sub_iters; j++) - { - if (ptrs[j] != NULL) - { - for (size_t k = 0; k < sizes[j]; k++) - { - TEST_ASSERT (ptrs[j][k] == 0); - } - - jmem_heap_free_block (ptrs[j], sizes[j]); - - ptrs[j] = NULL; - } - } - } - -#ifdef JMEM_STATS - jmem_heap_stats_print (); -#endif /* JMEM_STATS */ - - return 0; -} /* main */ diff --git a/tests/unit-core/test-objects-foreach.c b/tests/unit-core/test-objects-foreach.c index d4a7207f1..c291a2946 100644 --- a/tests/unit-core/test-objects-foreach.c +++ b/tests/unit-core/test-objects-foreach.c @@ -99,7 +99,7 @@ main (void) jerry_release_value (object); /* Collect garbage. */ - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); /* Attempt to retrieve the object by its native pointer again. */ TEST_ASSERT (!jerry_objects_foreach_by_native_info (&test_info, find_test_object_by_data, &found_object)); @@ -124,7 +124,7 @@ main (void) jerry_release_value (args[1]); /* Collect garbage. */ - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); /* Attempt to retrieve the object by the presence of its property again. */ args[0] = property_name; diff --git a/tests/unit-ext/test-ext-autorelease.c b/tests/unit-ext/test-ext-autorelease.c index 73de07f65..36df3db25 100644 --- a/tests/unit-ext/test-ext-autorelease.c +++ b/tests/unit-ext/test-ext-autorelease.c @@ -57,7 +57,7 @@ main (void) native_free_cb_call_count = 0; test_autorelease_val (); - jerry_gc (JERRY_GC_SEVERITY_HIGH); + jerry_gc (JERRY_GC_PRESSURE_HIGH); TEST_ASSERT (native_free_cb_call_count == 1); jerry_cleanup (); diff --git a/tests/unit-ext/test-ext-handle-scope-escape.c b/tests/unit-ext/test-ext-handle-scope-escape.c index 4d653ff13..24c93c670 100644 --- a/tests/unit-ext/test-ext-handle-scope-escape.c +++ b/tests/unit-ext/test-ext-handle-scope-escape.c @@ -61,7 +61,7 @@ test_handle_scope_val (void) jerry_value_t obj = create_object (); (void) obj; - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == 0); jerryx_close_handle_scope (scope); @@ -75,7 +75,7 @@ main (void) native_free_cb_call_count = 0; test_handle_scope_val (); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == 1); jerry_cleanup (); diff --git a/tests/unit-ext/test-ext-handle-scope-handle-prelist-escape.c b/tests/unit-ext/test-ext-handle-scope-handle-prelist-escape.c index a2c382e1f..4eec761ba 100644 --- a/tests/unit-ext/test-ext-handle-scope-handle-prelist-escape.c +++ b/tests/unit-ext/test-ext-handle-scope-handle-prelist-escape.c @@ -68,7 +68,7 @@ test_handle_scope_val (void) jerry_value_t obj = create_object (); (void) obj; - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == (handle_count -1)); jerryx_close_handle_scope (scope); @@ -82,7 +82,7 @@ main (void) native_free_cb_call_count = 0; test_handle_scope_val (); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == handle_count); jerry_cleanup (); diff --git a/tests/unit-ext/test-ext-handle-scope-handle-prelist.c b/tests/unit-ext/test-ext-handle-scope-handle-prelist.c index 995e6f307..d8b6707cc 100644 --- a/tests/unit-ext/test-ext-handle-scope-handle-prelist.c +++ b/tests/unit-ext/test-ext-handle-scope-handle-prelist.c @@ -68,7 +68,7 @@ test_handle_scope_val (void) jerry_value_t obj = create_object (); (void) obj; - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == (handle_count -1)); jerryx_close_handle_scope (scope); @@ -82,7 +82,7 @@ main (void) native_free_cb_call_count = 0; test_handle_scope_val (); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == handle_count); jerry_cleanup (); diff --git a/tests/unit-ext/test-ext-handle-scope-nested.c b/tests/unit-ext/test-ext-handle-scope-nested.c index 850a532e4..d96591cab 100644 --- a/tests/unit-ext/test-ext-handle-scope-nested.c +++ b/tests/unit-ext/test-ext-handle-scope-nested.c @@ -81,7 +81,7 @@ test_handle_scope_val (void) TEST_ASSERT (jerryx_handle_scope_get_current () == scope); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == 0); jerryx_close_handle_scope (scope); @@ -95,7 +95,7 @@ main (void) native_free_cb_call_count = 0; test_handle_scope_val (); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == 2); jerry_cleanup (); diff --git a/tests/unit-ext/test-ext-handle-scope-remove.c b/tests/unit-ext/test-ext-handle-scope-remove.c index 56b65cf9c..7f8d592b7 100644 --- a/tests/unit-ext/test-ext-handle-scope-remove.c +++ b/tests/unit-ext/test-ext-handle-scope-remove.c @@ -61,15 +61,15 @@ test_handle_scope_val (void) jerry_value_t obj = create_object (); (void) obj; - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == 0); jerryx_close_handle_scope (scope); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == 0); jerry_release_value (obj); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == 1); } /* test_handle_scope_val */ diff --git a/tests/unit-ext/test-ext-handle-scope-root.c b/tests/unit-ext/test-ext-handle-scope-root.c index 6e3c11b2b..a3c2a3da5 100644 --- a/tests/unit-ext/test-ext-handle-scope-root.c +++ b/tests/unit-ext/test-ext-handle-scope-root.c @@ -54,7 +54,7 @@ test_handle_scope_val (void) jerry_value_t obj = jerryx_create_handle (create_object ()); (void) obj; jerryx_close_handle_scope (root); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == (i + 1)); } } /* test_handle_scope_val */ @@ -67,7 +67,7 @@ main (void) native_free_cb_call_count = 0; test_handle_scope_val (); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == reusing_times); jerry_cleanup (); diff --git a/tests/unit-ext/test-ext-handle-scope.c b/tests/unit-ext/test-ext-handle-scope.c index 7fa056b12..9ed96842c 100644 --- a/tests/unit-ext/test-ext-handle-scope.c +++ b/tests/unit-ext/test-ext-handle-scope.c @@ -60,7 +60,7 @@ main (void) native_free_cb_call_count = 0; test_handle_scope_val (); - jerry_gc (JERRY_GC_SEVERITY_LOW); + jerry_gc (JERRY_GC_PRESSURE_LOW); TEST_ASSERT (native_free_cb_call_count == 1); jerry_cleanup ();