From 48f34adea5c691b65e17f6bfbd41a42cc84e0716 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Thu, 24 Oct 2019 14:49:47 +0200 Subject: [PATCH] General GC optimizations (#3221) - Enable recursive GC marking with a limited recursion count (this option is configurable) - No need to decrease the reference count of the gray objects anymore - Bound function object marking is seperated into a helper function JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- docs/01.CONFIGURATION.md | 13 +- jerry-core/CMakeLists.txt | 5 + jerry-core/config.h | 12 ++ jerry-core/ecma/base/ecma-gc.c | 177 ++++++++++++---------- jerry-core/ecma/base/ecma-globals.h | 25 ++- jerry-core/ecma/base/ecma-helpers.c | 4 +- jerry-core/ecma/base/ecma-init-finalize.c | 4 + jerry-core/jcontext/jcontext.h | 3 + tools/build.py | 5 + tools/run-tests.py | 20 ++- 10 files changed, 176 insertions(+), 92 deletions(-) diff --git a/docs/01.CONFIGURATION.md b/docs/01.CONFIGURATION.md index b74943451..cef99932c 100644 --- a/docs/01.CONFIGURATION.md +++ b/docs/01.CONFIGURATION.md @@ -211,6 +211,17 @@ A value of 0 will use the default value. | CMake: | `-DJERRY_GC_LIMIT=(int)` | | Python: | `--gc-limit=(int)` | +### GC mark recursion limit + +This option can be used to adjust the maximum recursion depth during the GC mark phase. The provided value should be an integer, which represents the allowed number of recursive calls. Increasing the depth of the recursion reduces the time of GC cycles, however increases stack usage. +A value of 0 will prevent any recursive GC calls. + +| Options | | +|---------|---------------------------------------------------| +| C: | `-DJERRY_GC_MARK_LIMIT=(int)` | +| CMake: | `-DJERRY_GC_MARK_LIMIT=(int)` | +| Python: | `--gc-mark-limit=(int)` | + ### Stack limit This option can be used to cap the stack usage of the engine, and prevent stack overflows due to recursion. The provided value should be an integer, which represents the allowed stack usage in kilobytes. @@ -296,7 +307,7 @@ These files can be directly compiled with an application using the JerryScript A For example with the following command: ```sh -$ gcc -Wall -o demo_app demo_app.c gen_src/jerryscript.c gen_src/jerryscript-port-default.c jerryscript-libm.c -Igen_src/ +$ gcc -Wall -o demo_app demo_app.c gen_src/jerryscript.c gen_src/jerryscript-port-default.c jerryscript-libm.c -Igen_src/ ``` Please note that the headers must be available on the include path. diff --git a/jerry-core/CMakeLists.txt b/jerry-core/CMakeLists.txt index 1cbc84283..240138f52 100644 --- a/jerry-core/CMakeLists.txt +++ b/jerry-core/CMakeLists.txt @@ -41,6 +41,7 @@ set(JERRY_VM_EXEC_STOP OFF CACHE BOOL "Enable VM execution st set(JERRY_GLOBAL_HEAP_SIZE "(512)" CACHE STRING "Size of memory heap, in kilobytes") set(JERRY_GC_LIMIT "(0)" CACHE STRING "Heap usage limit to trigger garbage collection") set(JERRY_STACK_LIMIT "(0)" CACHE STRING "Maximum stack usage size, in kilobytes") +set(JERRY_GC_MARK_LIMIT "(8)" CACHE STRING "Maximum depth of recursion during GC mark phase") # Option overrides if(USING_MSVC) @@ -104,6 +105,7 @@ message(STATUS "JERRY_VM_EXEC_STOP " ${JERRY_VM_EXEC_STOP}) message(STATUS "JERRY_GLOBAL_HEAP_SIZE " ${JERRY_GLOBAL_HEAP_SIZE}) message(STATUS "JERRY_GC_LIMIT " ${JERRY_GC_LIMIT}) message(STATUS "JERRY_STACK_LIMIT " ${JERRY_STACK_LIMIT}) +message(STATUS "JERRY_GC_MARK_LIMIT " ${JERRY_GC_MARK_LIMIT}) # Include directories set(INCLUDE_CORE_PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") @@ -305,6 +307,9 @@ set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_GLOBAL_HEAP_SIZE=${JERRY_GLOBAL_HEAP_SI # Maximum size of stack memory usage set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_STACK_LIMIT=${JERRY_STACK_LIMIT}) +# Maximum depth of recursion during GC mark phase +set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_GC_MARK_LIMIT=${JERRY_GC_MARK_LIMIT}) + ## This function is to read "config.h" for default values function(read_set_defines FILE PREFIX OUTPUTVAR) file(READ "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}" INPUT_FILE_CONTENTS) diff --git a/jerry-core/config.h b/jerry-core/config.h index 8563c8127..de97d24f4 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -201,6 +201,15 @@ # define JERRY_STACK_LIMIT (0) #endif /* !defined (JERRY_STACK_LIMIT) */ +/** + * Maximum depth of recursion during GC mark phase + * + * Default value: 8 + */ +#ifndef JERRY_GC_MARK_LIMIT +# define JERRY_GC_MARK_LIMIT (8) +#endif /* !defined (JERRY_GC_MARK_LIMIT) */ + /** * Enable/Disable property lookup cache. * @@ -572,6 +581,9 @@ #if !defined (JERRY_STACK_LIMIT) || (JERRY_STACK_LIMIT < 0) # error "Invalid value for 'JERRY_STACK_LIMIT' macro." #endif +#if !defined (JERRY_GC_MARK_LIMIT) || (JERRY_GC_MARK_LIMIT < 0) +# error "Invalid value for 'JERRY_GC_MARK_LIMIT' macro." +#endif #if !defined (JERRY_LCACHE) \ || ((JERRY_LCACHE != 0) && (JERRY_LCACHE != 1)) # error "Invalid value for 'JERRY_LCACHE' macro." diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 293ed7f8d..879d94999 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -64,30 +64,42 @@ ecma_gc_is_object_visited (ecma_object_t *object_p) /**< object */ { JERRY_ASSERT (object_p != NULL); - return (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE); + return (object_p->type_flags_refs < ECMA_OBJECT_NON_VISITED); } /* ecma_gc_is_object_visited */ /** - * Set visited flag of the object. - * Note: This macro can be inlined for performance critical code paths + * Mark objects as visited starting from specified object as root */ -#define ECMA_GC_SET_OBJECT_VISITED(object_p) \ - do \ - { \ - if ((object_p)->type_flags_refs < ECMA_OBJECT_REF_ONE) \ - { \ - (object_p)->type_flags_refs |= ECMA_OBJECT_REF_ONE; \ - } \ - } while (0) +static void ecma_gc_mark (ecma_object_t *object_p); /** * Set visited flag of the object. */ -static void JERRY_ATTR_NOINLINE +static void ecma_gc_set_object_visited (ecma_object_t *object_p) /**< object */ { - /* Set reference counter to one if it is zero. */ - ECMA_GC_SET_OBJECT_VISITED (object_p); + if (object_p->type_flags_refs >= ECMA_OBJECT_NON_VISITED) + { +#if (JERRY_GC_MARK_LIMIT != 0) + if (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) != 0) + { + JERRY_CONTEXT (ecma_gc_mark_recursion_limit)--; + /* Set the reference count of gray object to 0 */ + object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1)); + ecma_gc_mark (object_p); + JERRY_CONTEXT (ecma_gc_mark_recursion_limit)++; + } + else + { + /* Set the reference count of the non-marked gray object to 1 */ + object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & ((ECMA_OBJECT_REF_ONE << 1) - 1)); + JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE); + } +#else /* (JERRY_GC_MARK_LIMIT == 0) */ + /* Set the reference count of gray object to 0 */ + object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1)); +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ + } } /* ecma_gc_set_object_visited */ /** @@ -154,7 +166,7 @@ ecma_gc_mark_properties (ecma_property_pair_t *property_pair_p) /**< property pa { ecma_object_t *value_obj_p = ecma_get_object_from_value (value); - ECMA_GC_SET_OBJECT_VISITED (value_obj_p); + ecma_gc_set_object_visited (value_obj_p); } break; } @@ -193,8 +205,49 @@ ecma_gc_mark_properties (ecma_property_pair_t *property_pair_p) /**< property pa } } /* ecma_gc_mark_properties */ -#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) +/** + * Mark objects referenced by bound function object. + */ +static void JERRY_ATTR_NOINLINE +ecma_gc_mark_bound_function_object (ecma_object_t *object_p) /**< bound function object */ +{ + JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) object_p; + + ecma_object_t *target_func_obj_p; + target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + ext_function_p->u.bound_function.target_function); + + ecma_gc_set_object_visited (target_func_obj_p); + + ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this; + + if (!ecma_is_value_integer_number (args_len_or_this)) + { + if (ecma_is_value_object (args_len_or_this)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (args_len_or_this)); + } + + return; + } + + ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this); + ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1); + + JERRY_ASSERT (args_length > 0); + + for (ecma_integer_value_t i = 0; i < args_length; i++) + { + if (ecma_is_value_object (args_p[i])) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (args_p[i])); + } + } +} /* ecma_gc_mark_bound_function_object */ + +#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) /** * Mark objects referenced by Promise built-in. */ @@ -315,7 +368,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ if (outer_lex_env_cp != JMEM_CP_NULL) { - ECMA_GC_SET_OBJECT_VISITED (ECMA_GET_NON_NULL_POINTER (ecma_object_t, outer_lex_env_cp)); + ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, outer_lex_env_cp)); } if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) @@ -332,7 +385,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ if (proto_cp != JMEM_CP_NULL) { - ECMA_GC_SET_OBJECT_VISITED (ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp)); + ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp)); } switch (ecma_get_object_type (object_p)) @@ -431,18 +484,16 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ if (ext_object_p->u.array.is_fast_mode) { - if (object_p->u1.property_list_cp == JMEM_CP_NULL) + if (object_p->u1.property_list_cp != JMEM_CP_NULL) { - return; - } + ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); - ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); - - for (uint32_t i = 0; i < ext_object_p->u.array.length; i++) - { - if (ecma_is_value_object (values_p[i])) + for (uint32_t i = 0; i < ext_object_p->u.array.length; i++) { - ECMA_GC_SET_OBJECT_VISITED (ecma_get_object_from_value (values_p[i])); + if (ecma_is_value_object (values_p[i])) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (values_p[i])); + } } } @@ -452,37 +503,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ } case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) object_p; - - ecma_object_t *target_func_obj_p; - target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_function_p->u.bound_function.target_function); - - ecma_gc_set_object_visited (target_func_obj_p); - - ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this; - - if (!ecma_is_value_integer_number (args_len_or_this)) - { - if (ecma_is_value_object (args_len_or_this)) - { - ecma_gc_set_object_visited (ecma_get_object_from_value (args_len_or_this)); - } - break; - } - - ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this); - ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1); - - JERRY_ASSERT (args_length > 0); - - for (ecma_integer_value_t i = 0; i < args_length; i++) - { - if (ecma_is_value_object (args_p[i])) - { - ecma_gc_set_object_visited (ecma_get_object_from_value (args_p[i])); - } - } + ecma_gc_mark_bound_function_object (object_p); break; } case ECMA_OBJECT_TYPE_FUNCTION: @@ -491,7 +512,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - ECMA_GC_SET_OBJECT_VISITED (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + ecma_gc_set_object_visited (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_func_p->u.function.scope_cp)); } break; @@ -623,7 +644,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ { JERRY_ASSERT (object_p != NULL && !ecma_gc_is_object_visited (object_p) - && object_p->type_flags_refs < ECMA_OBJECT_REF_ONE); + && ((object_p->type_flags_refs & ECMA_OBJECT_REF_MASK) == ECMA_OBJECT_NON_VISITED)); bool obj_is_not_lex_env = !ecma_is_lexical_environment (object_p); @@ -984,6 +1005,10 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ void ecma_gc_run (void) { +#if (JERRY_GC_MARK_LIMIT != 0) + JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) == JERRY_GC_MARK_LIMIT); +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ + JERRY_CONTEXT (ecma_gc_new_objects) = 0; ecma_object_t black_list_head; @@ -1006,7 +1031,7 @@ ecma_gc_run (void) JERRY_ASSERT (obj_prev_p == NULL || ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_prev_p->gc_next_cp) == obj_iter_p); - if (ecma_gc_is_object_visited (obj_iter_p)) + if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE) { /* Moving the object to list of marked objects. */ obj_prev_p->gc_next_cp = obj_next_cp; @@ -1016,6 +1041,7 @@ ecma_gc_run (void) } else { + obj_iter_p->type_flags_refs |= ECMA_OBJECT_NON_VISITED; obj_prev_p = obj_iter_p; } @@ -1023,7 +1049,6 @@ ecma_gc_run (void) } black_end_p->gc_next_cp = JMEM_CP_NULL; - ecma_object_t *const last_root_object_p = black_end_p; /* Mark root objects. */ obj_iter_cp = black_list_head.gc_next_cp; @@ -1039,6 +1064,10 @@ ecma_gc_run (void) do { +#if (JERRY_GC_MARK_LIMIT != 0) + JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) == JERRY_GC_MARK_LIMIT); +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ + marked_anything_during_current_iteration = false; obj_prev_p = &white_gray_list_head; @@ -1060,8 +1089,17 @@ ecma_gc_run (void) black_end_p->gc_next_cp = obj_iter_cp; black_end_p = obj_iter_p; - ecma_gc_mark (obj_iter_p); +#if (JERRY_GC_MARK_LIMIT != 0) + if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE) + { + /* Set the reference count of non-marked gray object to 0 */ + obj_iter_p->type_flags_refs = (uint16_t) (obj_iter_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1)); + ecma_gc_mark (obj_iter_p); + marked_anything_during_current_iteration = true; + } +#else /* (JERRY_GC_MARK_LIMIT == 0) */ marked_anything_during_current_iteration = true; +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ } else { @@ -1089,19 +1127,6 @@ ecma_gc_run (void) obj_iter_cp = obj_next_cp; } - /* Reset the reference counter of non-root black objects. */ - obj_iter_cp = last_root_object_p->gc_next_cp; - - while (obj_iter_cp != JMEM_CP_NULL) - { - /* The reference counter must be 1. */ - obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp); - ecma_deref_object (obj_iter_p); - JERRY_ASSERT (obj_iter_p->type_flags_refs < ECMA_OBJECT_REF_ONE); - - obj_iter_cp = obj_iter_p->gc_next_cp; - } - JERRY_CONTEXT (ecma_gc_objects_cp) = black_list_head.gc_next_cp; #if ENABLED (JERRY_BUILTIN_REGEXP) diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 40306c988..7f22ef0bd 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -714,14 +714,29 @@ typedef enum #endif /* ENABLED (JERRY_DEBUGGER) */ /** - * Value for increasing or decreasing the object reference counter. + * Bitshift index for an ecma-object reference count field */ -#define ECMA_OBJECT_REF_ONE (1u << 6) +#define ECMA_OBJECT_REF_SHIFT 6 /** - * Maximum value of the object reference counter (1023). + * Bitmask for an ecma-object reference count field */ -#define ECMA_OBJECT_MAX_REF (0x3ffu << 6) +#define ECMA_OBJECT_REF_MASK (((1u << 10) - 1) << ECMA_OBJECT_REF_SHIFT) + +/** + * Value for increasing or decreasing the object reference counter. + */ +#define ECMA_OBJECT_REF_ONE (1u << ECMA_OBJECT_REF_SHIFT) + +/** + * Represents non-visited white object + */ +#define ECMA_OBJECT_NON_VISITED (0x3ffu << ECMA_OBJECT_REF_SHIFT) + +/** + * Maximum value of the object reference counter (1022). + */ +#define ECMA_OBJECT_MAX_REF (ECMA_OBJECT_NON_VISITED - ECMA_OBJECT_REF_ONE) /** * Description of ECMA-object or lexical environment @@ -733,7 +748,7 @@ typedef struct depending on ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV flags : 2 bit : ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV, ECMA_OBJECT_FLAG_EXTENSIBLE or ECMA_OBJECT_FLAG_NON_CLOSURE - refs : 10 bit (max 1023) */ + refs : 10 bit (max 1022) */ uint16_t type_flags_refs; /** next in the object chain maintained by the garbage collector */ diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 15fcca8f6..003c72785 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -54,8 +54,8 @@ JERRY_STATIC_ASSERT (ECMA_OBJECT_FLAG_EXTENSIBLE == (ECMA_OBJECT_FLAG_BUILT_IN_O JERRY_STATIC_ASSERT (ECMA_OBJECT_REF_ONE == (ECMA_OBJECT_FLAG_EXTENSIBLE << 1), ecma_object_ref_one_must_follow_the_extensible_flag); -JERRY_STATIC_ASSERT ((ECMA_OBJECT_MAX_REF | (ECMA_OBJECT_REF_ONE - 1)) == UINT16_MAX, - ecma_object_max_ref_does_not_fill_the_remaining_bits); +JERRY_STATIC_ASSERT (((ECMA_OBJECT_MAX_REF + ECMA_OBJECT_REF_ONE) | (ECMA_OBJECT_REF_ONE - 1)) == UINT16_MAX, + ecma_object_max_ref_does_not_fill_the_remaining_bits); JERRY_STATIC_ASSERT (ECMA_PROPERTY_TYPE_DELETED == (ECMA_DIRECT_STRING_MAGIC << ECMA_PROPERTY_NAME_TYPE_SHIFT), ecma_property_type_deleted_must_have_magic_string_name_type); diff --git a/jerry-core/ecma/base/ecma-init-finalize.c b/jerry-core/ecma/base/ecma-init-finalize.c index 383c2f39c..5a78cc2cc 100644 --- a/jerry-core/ecma/base/ecma-init-finalize.c +++ b/jerry-core/ecma/base/ecma-init-finalize.c @@ -47,6 +47,10 @@ ecma_init (void) JERRY_CONTEXT (stack_base) = (uintptr_t)&sp; #endif /* (JERRY_STACK_LIMIT != 0) */ +#if (JERRY_GC_MARK_LIMIT != 0) + JERRY_CONTEXT (ecma_gc_mark_recursion_limit) = JERRY_GC_MARK_LIMIT; +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ + #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) ecma_job_queue_init (); #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 16f29aaf7..0c7e4abc0 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -159,6 +159,9 @@ struct jerry_context_t uint32_t lit_magic_string_ex_count; /**< external magic strings count */ uint32_t jerry_init_flags; /**< run-time configuration flags */ uint32_t status_flags; /**< run-time flags (the top 8 bits are used for passing class parsing options) */ +#if (JERRY_GC_MARK_LIMIT != 0) + uint32_t ecma_gc_mark_recursion_limit; /**< GC mark recursion limit */ +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ #if ENABLED (JERRY_PROPRETY_HASHMAP) uint8_t ecma_prop_hashmap_alloc_state; /**< property hashmap allocation state: 0-4, diff --git a/tools/build.py b/tools/build.py index 52c2bc8fc..e30f00e4a 100755 --- a/tools/build.py +++ b/tools/build.py @@ -128,6 +128,8 @@ def get_arguments(): help='memory usage limit to trigger garbage collection (in bytes)') coregrp.add_argument('--stack-limit', metavar='SIZE', type=int, help='maximum stack usage (in kilobytes)') + coregrp.add_argument('--gc-mark-limit', metavar='SIZE', type=int, + help='maximum depth of recursion during GC mark phase') coregrp.add_argument('--mem-stats', metavar='X', choices=['ON', 'OFF'], type=str.upper, help=devhelp('enable memory statistics (%(choices)s)')) coregrp.add_argument('--mem-stress-test', metavar='X', choices=['ON', 'OFF'], type=str.upper, @@ -215,6 +217,9 @@ def generate_build_options(arguments): build_options_append('JERRY_VALGRIND', arguments.valgrind) build_options_append('JERRY_VM_EXEC_STOP', arguments.vm_exec_stop) + if arguments.gc_mark_limit is not None: + build_options.append('-D%s=%s' % ('JERRY_GC_MARK_LIMIT', arguments.gc_mark_limit)) + # jerry-main options build_options_append('ENABLE_LINK_MAP', arguments.link_map) diff --git a/tools/run-tests.py b/tools/run-tests.py index e37899aaf..76c9265ed 100755 --- a/tools/run-tests.py +++ b/tools/run-tests.py @@ -38,6 +38,7 @@ OPTIONS_PROFILE_MIN = ['--profile=minimal'] OPTIONS_PROFILE_ES51 = [] # NOTE: same as ['--profile=es5.1'] OPTIONS_PROFILE_ES2015 = ['--profile=es2015-subset'] OPTIONS_STACK_LIMIT = ['--stack-limit=96'] +OPTIONS_GC_MARK_LIMIT = ['--gc-mark-limit=16'] OPTIONS_DEBUG = ['--debug'] OPTIONS_SNAPSHOT = ['--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on'] OPTIONS_UNITTESTS = ['--unittests=on', '--jerry-cmdline=off', '--error-messages=on', @@ -75,22 +76,23 @@ JERRY_UNITTESTS_OPTIONS = [ # Test options for jerry-tests JERRY_TESTS_OPTIONS = [ Options('jerry_tests-es2015_subset-debug', - OPTIONS_COMMON + OPTIONS_PROFILE_ES2015 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT), + OPTIONS_COMMON + OPTIONS_PROFILE_ES2015 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT), Options('jerry_tests-es5.1', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_STACK_LIMIT), + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT), Options('jerry_tests-es5.1-snapshot', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_SNAPSHOT + OPTIONS_STACK_LIMIT, + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_SNAPSHOT + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT, ['--snapshot']), Options('jerry_tests-es5.1-debug', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT), + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT), Options('jerry_tests-es5.1-debug-snapshot', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_SNAPSHOT + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT, - ['--snapshot']), + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_SNAPSHOT + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + + OPTIONS_GC_MARK_LIMIT, ['--snapshot']), Options('jerry_tests-es5.1-debug-cpointer_32bit', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT + ['--cpointer-32bit=on', '--mem-heap=1024']), Options('jerry_tests-es5.1-debug-external_context', - OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + ['--external-context=on']), + OPTIONS_COMMON + OPTIONS_PROFILE_ES51 + OPTIONS_DEBUG + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT + + ['--external-context=on']), ] # Test options for jerry-test-suite @@ -169,6 +171,8 @@ JERRY_BUILDOPTIONS = [ ['--jerry-cmdline-snapshot=on']), Options('buildoption_test-recursion_limit', OPTIONS_STACK_LIMIT), + Options('buildoption_test-gc-mark_limit', + OPTIONS_GC_MARK_LIMIT), Options('buildoption_test-single-source', ['--cmake-param=-DENABLE_ALL_IN_ONE_SOURCE=ON']), ]