diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index c6fb9004a4..1aea8d8dad 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -366,6 +366,15 @@ typedef struct parser_branch_node_t parser_branch_t branch; /**< branch */ } parser_branch_node_t; +/** + * Linked list to store branch data. + */ +typedef struct parser_branch_list_t +{ + struct parser_branch_list_t *next_p; /**< next branch */ + parser_branch_node_t *branch_node_p; /**< branch node */ +} parser_branch_list_t; + /** * Items of scope stack. */ @@ -591,6 +600,7 @@ typedef struct ecma_value_t tagged_template_literal_cp; /**< compessed pointer to the tagged template literal collection */ parser_private_context_t *private_context_p; /**< private context */ uint8_t stack_top_uint8; /**< top byte stored on the stack */ + parser_branch_list_t *branch_list; /**< list of branches */ #ifndef JERRY_NDEBUG /* Variables for debugging / logging. */ @@ -654,6 +664,11 @@ void *parser_list_get (parser_list_t *list_p, size_t index); void parser_list_iterator_init (parser_list_t *list_p, parser_list_iterator_t *iterator_p); void *parser_list_iterator_next (parser_list_iterator_t *iterator_p); +void parser_branch_list_init (parser_context_t *context_p); +void *parser_branch_list_append (parser_context_t *context_p); +void parser_branch_list_remove (const parser_context_t *context_p, const parser_branch_node_t *node_p); +void parser_branch_list_free (const parser_context_t *context_p); + /* Parser stack. Optimized for pushing bytes. * Pop functions never throws error. */ diff --git a/jerry-core/parser/js/js-parser-mem.c b/jerry-core/parser/js/js-parser-mem.c index 14f87c2c4e..7679ea6eca 100644 --- a/jerry-core/parser/js/js-parser-mem.c +++ b/jerry-core/parser/js/js-parser-mem.c @@ -327,6 +327,105 @@ parser_list_iterator_next (parser_list_iterator_t *iterator_p) /**< iterator */ return result; } /* parser_list_iterator_next */ +/* + * Init branch linked list. + */ +void +parser_branch_list_init (parser_context_t *context_p) +{ + context_p->branch_list = (parser_branch_list_t *) parser_malloc (context_p, sizeof (parser_branch_list_t)); + context_p->branch_list->branch_node_p = NULL; + context_p->branch_list->next_p = NULL; +} /* parser_branch_list_init */ + +/** + * Append a branch node to the branch list. + * + * @return the newly created branch node. + */ +void * +parser_branch_list_append (parser_context_t *context_p) +{ + parser_branch_node_t *result = parser_malloc (context_p, sizeof (parser_branch_node_t)); + + if (result == NULL) + { + return NULL; + } + + parser_branch_list_t *last_pos = context_p->branch_list; + while (last_pos->next_p != NULL) + { + last_pos = last_pos->next_p; + } + + last_pos->next_p = (parser_branch_list_t *) parser_malloc (context_p, sizeof (parser_branch_list_t)); + last_pos->next_p->branch_node_p = result; + last_pos->next_p->next_p = NULL; + + return result; +} /* parser_branch_list_append */ + +/** + * Remove a branch node from the branch list. + */ +void +parser_branch_list_remove (const parser_context_t *context_p, const parser_branch_node_t *node_p) +{ + parser_branch_list_t *pos = context_p->branch_list; + parser_branch_list_t *prev_pos = NULL; + + while (pos->next_p != NULL && pos->branch_node_p != node_p) + { + prev_pos = pos; + pos = pos->next_p; + } + + if (pos->branch_node_p != node_p) + { + return; + } + + parser_branch_list_t *next_pos = pos->next_p; + + parser_free (pos->branch_node_p, sizeof (parser_branch_node_t)); + + if (prev_pos == NULL && next_pos == NULL) + { + context_p->branch_list->branch_node_p = NULL; + return; + } + + parser_free (pos, sizeof (parser_branch_list_t)); + + if (prev_pos != NULL) + { + prev_pos->next_p = next_pos; + } +} /* parser_branch_list_remove */ + +/** + * Free the branch list. + */ +void +parser_branch_list_free (const parser_context_t *context_p) +{ + parser_branch_list_t *pos = context_p->branch_list; + parser_branch_list_t *prev_pos = NULL; + + while (pos != NULL) + { + prev_pos = pos; + pos = pos->next_p; + if (prev_pos->branch_node_p != NULL) + { + parser_free (prev_pos->branch_node_p, sizeof (parser_branch_node_t)); + } + + parser_free (prev_pos, sizeof (parser_branch_list_t)); + } +} /* parser_branch_list_free */ + /**********************************************************************/ /* Parser stack management functions */ /**********************************************************************/ diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 10df37e514..15f5e214e2 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -2053,7 +2053,7 @@ parser_parse_case_statement (parser_context_t *context_p) /**< context */ parser_stack_iterator_write (&iterator, &switch_statement, sizeof (parser_switch_statement_t)); parser_set_branch_to_current_position (context_p, &branch_p->branch); - parser_free (branch_p, sizeof (parser_branch_node_t)); + parser_branch_list_remove (context_p, branch_p); } /* parser_parse_case_statement */ /** diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index c3ba131d69..21a1af75e6 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -540,7 +540,7 @@ parser_emit_cbc_forward_branch_item (parser_context_t *context_p, /**< context * * the branch is constructed locally, and copied later. */ parser_emit_cbc_forward_branch (context_p, opcode, &branch); - new_item = (parser_branch_node_t *) parser_malloc (context_p, sizeof (parser_branch_node_t)); + new_item = (parser_branch_node_t *) parser_branch_list_append (context_p); new_item->branch = branch; new_item->next_p = next_p; return new_item; @@ -730,7 +730,7 @@ parser_set_breaks_to_current_position (parser_context_t *context_p, /**< context { parser_set_branch_to_current_position (context_p, ¤t_p->branch); } - parser_free (current_p, sizeof (parser_branch_node_t)); + parser_branch_list_remove (context_p, current_p); current_p = next_p; } } /* parser_set_breaks_to_current_position */ diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 8f241b6a1a..a61195afd2 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -2140,6 +2140,7 @@ parser_parse_source (void *source_p, /**< source code */ context.scope_stack_global_end = 0; context.tagged_template_literal_cp = JMEM_CP_NULL; context.private_context_p = NULL; + parser_branch_list_init (&context); #ifndef JERRY_NDEBUG context.context_stack_depth = 0; @@ -2293,6 +2294,7 @@ parser_parse_source (void *source_p, /**< source code */ JERRY_ASSERT (!(context.status_flags & PARSER_HAS_LATE_LIT_INIT)); compiled_code_p = parser_post_processing (&context); + parser_branch_list_free (&context); parser_list_free (&context.literal_pool); /* When parsing is successful, only the dummy value can be remained on the stack. */ @@ -2366,11 +2368,6 @@ parser_parse_source (void *source_p, /**< source code */ } PARSER_CATCH { - if (context.last_statement.current_p != NULL) - { - parser_free_jumps (context.last_statement); - } - parser_free_allocated_buffer (&context); scanner_cleanup (&context); @@ -2383,6 +2380,7 @@ parser_parse_source (void *source_p, /**< source code */ #endif /* JERRY_MODULE_SYSTEM */ compiled_code_p = NULL; + parser_branch_list_free (&context); parser_free_literals (&context.literal_pool); parser_cbc_stream_free (&context.byte_code); diff --git a/tests/jerry/fail/regression-test-issue-5062.js b/tests/jerry/fail/regression-test-issue-5062.js new file mode 100644 index 0000000000..9d29a42b7f --- /dev/null +++ b/tests/jerry/fail/regression-test-issue-5062.js @@ -0,0 +1,15 @@ +// 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. + +( async ( ) => { for await ( const b of n ) { continue ; diff --git a/tools/run-tests.py b/tools/run-tests.py index 64bc1ed827..f72b814c77 100755 --- a/tools/run-tests.py +++ b/tools/run-tests.py @@ -50,6 +50,7 @@ def skip_if(condition, desc): OPTIONS_DOCTESTS = ['--doctests=on', '--jerry-cmdline=off', '--error-messages=on', '--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on'] OPTIONS_PROMISE_CALLBACK = ['--promise-callback=on'] +OPTIONS_HEAP_SIZE = ['--mem-heap=1024'] # Test options for unittests JERRY_UNITTESTS_OPTIONS = [ @@ -67,15 +68,15 @@ def skip_if(condition, desc): # Test options for jerry-tests JERRY_TESTS_OPTIONS = [ Options('jerry_tests', - OPTIONS_COMMON + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT + OPTIONS_MEM_STRESS), + OPTIONS_COMMON + OPTIONS_STACK_LIMIT + OPTIONS_HEAP_SIZE + OPTIONS_GC_MARK_LIMIT + OPTIONS_MEM_STRESS), Options('jerry_tests-snapshot', - OPTIONS_COMMON + OPTIONS_SNAPSHOT + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT, + OPTIONS_COMMON + OPTIONS_SNAPSHOT + OPTIONS_HEAP_SIZE + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT, ['--snapshot']), Options('jerry_tests-cpointer_32bit', - OPTIONS_COMMON + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT - + ['--cpointer-32bit=on', '--mem-heap=1024']), + OPTIONS_COMMON + OPTIONS_STACK_LIMIT + OPTIONS_HEAP_SIZE + OPTIONS_GC_MARK_LIMIT + + ['--cpointer-32bit=on']), Options('jerry_tests-external_context', - OPTIONS_COMMON + OPTIONS_STACK_LIMIT + OPTIONS_GC_MARK_LIMIT + OPTIONS_COMMON + OPTIONS_STACK_LIMIT + OPTIONS_HEAP_SIZE + OPTIONS_GC_MARK_LIMIT + ['--external-context=on']), ]