From 76b8555210cbccd60322aa0db666822f890a39c2 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Fri, 27 Mar 2020 11:21:50 +0100 Subject: [PATCH] Remove JERRY_CONTEXT_INVALID_NEW_TARGET (#3643) Until now JERRY_CONTEXT_INVALID_NEW_TARGET was used to represent whether the eval called from the script directly. This information can be retrieved from the parser, so it simplifies the runtime handling of the new.target. This patch fixes #3630, fixes #3640 and fixes #3641. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- jerry-core/api/jerry.c | 2 +- jerry-core/ecma/base/ecma-globals.h | 4 +-- jerry-core/ecma/base/ecma-init-finalize.c | 4 +-- jerry-core/ecma/operations/ecma-eval.c | 7 ----- .../ecma/operations/ecma-function-object.c | 8 ++---- jerry-core/jcontext/jcontext.h | 6 ----- jerry-core/parser/js/js-parser-expr.c | 13 ++++------ jerry-core/parser/js/js-parser-internal.h | 12 ++++----- jerry-core/parser/js/js-parser-statm.c | 7 +---- jerry-core/parser/js/js-parser.c | 9 ++++--- jerry-core/vm/opcodes.c | 3 --- jerry-core/vm/vm.c | 1 - .../es2015/regression-test-issue-3630.js | 23 ++++++++++++++++ .../es2015/regression-test-issue-3640.js | 23 ++++++++++++++++ .../es2015/regression-test-issue-3641.js | 26 +++++++++++++++++++ 15 files changed, 96 insertions(+), 52 deletions(-) create mode 100644 tests/jerry/es2015/regression-test-issue-3630.js create mode 100644 tests/jerry/es2015/regression-test-issue-3640.js create mode 100644 tests/jerry/es2015/regression-test-issue-3641.js diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 35f52ab0c..362a13435 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -3585,7 +3585,7 @@ jerry_get_new_target (void) #if ENABLED (JERRY_ES2015) ecma_object_t *current_new_target = JERRY_CONTEXT (current_new_target); - if (current_new_target == NULL || current_new_target == JERRY_CONTEXT_INVALID_NEW_TARGET) + if (current_new_target == NULL) { return jerry_create_undefined (); } diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index dd85aa5ff..ae207cae2 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -111,13 +111,13 @@ typedef enum ECMA_PARSE_EVAL = (1u << 2), /**< eval is called */ ECMA_PARSE_DIRECT_EVAL = (1u << 3), /**< eval is called directly (ECMA-262 v5, 15.1.2.1.1) */ - /* These three status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */ + /* These 4 status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */ ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 4), /**< a class constructor is being parsed (this value must be kept in * in sync with PARSER_CLASS_CONSTRUCTOR) */ ECMA_PARSE_ALLOW_SUPER = (1u << 5), /**< allow super property access */ ECMA_PARSE_ALLOW_SUPER_CALL = (1u << 6), /**< allow super constructor call */ + ECMA_PARSE_ALLOW_NEW_TARGET = (1u << 7), /**< allow new.target access */ - ECMA_PARSE_CALLED_FROM_FUNCTION = (1u << 7), /**< a function body is parsed or the code is inside a function */ ECMA_PARSE_GENERATOR_FUNCTION = (1u << 8), /**< generator function is parsed */ /* These flags are internally used by the parser. */ diff --git a/jerry-core/ecma/base/ecma-init-finalize.c b/jerry-core/ecma/base/ecma-init-finalize.c index e0bca19f3..6e67eb22c 100644 --- a/jerry-core/ecma/base/ecma-init-finalize.c +++ b/jerry-core/ecma/base/ecma-init-finalize.c @@ -61,7 +61,7 @@ ecma_init (void) #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ #if ENABLED (JERRY_ES2015) - JERRY_CONTEXT (current_new_target) = JERRY_CONTEXT_INVALID_NEW_TARGET; + JERRY_CONTEXT (current_new_target) = NULL; JERRY_CONTEXT (current_function_obj_p) = NULL; #endif /* ENABLED (JERRY_ES2015) */ } /* ecma_init */ @@ -73,7 +73,7 @@ void ecma_finalize (void) { #if ENABLED (JERRY_ES2015) - JERRY_ASSERT (JERRY_CONTEXT (current_new_target) == JERRY_CONTEXT_INVALID_NEW_TARGET); + JERRY_ASSERT (JERRY_CONTEXT (current_new_target) == NULL); JERRY_ASSERT (JERRY_CONTEXT (current_function_obj_p) == NULL); #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/operations/ecma-eval.c b/jerry-core/ecma/operations/ecma-eval.c index 2759236db..69cc4546e 100644 --- a/jerry-core/ecma/operations/ecma-eval.c +++ b/jerry-core/ecma/operations/ecma-eval.c @@ -99,13 +99,6 @@ ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters b #if ENABLED (JERRY_ES2015) ECMA_CLEAR_LOCAL_PARSE_OPTS (); - - /* If a direct eval is used inside the function the info should be propagated. */ - if (JERRY_CONTEXT (current_new_target) != JERRY_CONTEXT_INVALID_NEW_TARGET - && (JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL)) - { - parse_opts |= ECMA_PARSE_CALLED_FROM_FUNCTION; - } #endif /* ENABLED (JERRY_ES2015) */ ecma_value_t parse_status = parser_parse_script (NULL, diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index b2bcda531..dadd26ba1 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -445,11 +445,7 @@ ecma_op_create_arrow_function_object (ecma_object_t *scope_p, /**< function's sc arrow_func_p->this_binding = ecma_copy_value_if_not_object (this_binding); arrow_func_p->new_target = ECMA_VALUE_UNDEFINED; - if (JERRY_CONTEXT (current_new_target) == JERRY_CONTEXT_INVALID_NEW_TARGET) - { - arrow_func_p->new_target = ECMA_VALUE_EMPTY; - } - else if (JERRY_CONTEXT (current_new_target) != NULL) + if (JERRY_CONTEXT (current_new_target) != NULL) { arrow_func_p->new_target = ecma_make_object_value (JERRY_CONTEXT (current_new_target)); } @@ -792,7 +788,7 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ { JERRY_CONTEXT (current_new_target) = NULL; } - else if (ecma_is_value_object (arrow_func_p->new_target)) + else { JERRY_CONTEXT (current_new_target) = ecma_get_object_from_value (arrow_func_p->new_target); } diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 5f3f02ebb..ba3bf376a 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -228,7 +228,6 @@ struct jerry_context_t /** * Allowed values and it's meaning: * * NULL (0x0): the current "new.target" is undefined, that is the execution is inside a normal method. - * * JERRY_CONTEXT_INVALID_NEW_TARGET (0x1): the current "new.target" is invalid, that is outside of a method. * * Any other valid function object pointer: the current "new.target" is valid and it is constructor call. */ ecma_object_t *current_new_target; @@ -237,11 +236,6 @@ struct jerry_context_t #endif /* ENABLED (JERRY_ES2015) */ }; -/** - * Magic constant used to indicate that the current "new.target" is not inside a function. - */ -#define JERRY_CONTEXT_INVALID_NEW_TARGET ((ecma_object_t *) 0x1) - #if ENABLED (JERRY_EXTERNAL_CONTEXT) /* diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 1ab724a75..1cac8aff9 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -1439,8 +1439,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ /* Check if "new.target" is written here. */ if (scanner_try_scan_new_target (context_p)) { - if (!(context_p->status_flags & PARSER_ALLOW_NEW_TARGET) - && !(context_p->global_status_flags & ECMA_PARSE_CALLED_FROM_FUNCTION)) + if (!(context_p->status_flags & PARSER_ALLOW_NEW_TARGET)) { parser_raise_error (context_p, PARSER_ERR_NEW_TARGET_NOT_ALLOWED); } @@ -1505,7 +1504,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ } parser_check_assignment_expr (context_p); - parser_parse_function_expression (context_p, PARSER_IS_ARROW_FUNCTION); + parser_parse_function_expression (context_p, PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); return parser_abort_parsing_after_arrow (context_p); } #endif /* ENABLED (JERRY_ES2015) */ @@ -1682,9 +1681,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ { if (context_p->status_flags & PARSER_ALLOW_SUPER) { - if (lexer_check_next_characters (context_p, LIT_CHAR_DOT, LIT_CHAR_LEFT_SQUARE) - && ((context_p->status_flags & PARSER_ALLOW_NEW_TARGET) - || (context_p->global_status_flags & ECMA_PARSE_CALLED_FROM_FUNCTION))) + if (lexer_check_next_characters (context_p, LIT_CHAR_DOT, LIT_CHAR_LEFT_SQUARE)) { parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SUPER); break; @@ -1708,7 +1705,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ parser_check_assignment_expr (context_p); context_p->token.type = LEXER_ARROW_LEFT_PAREN; - parser_parse_function_expression (context_p, PARSER_IS_ARROW_FUNCTION); + parser_parse_function_expression (context_p, PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); return parser_abort_parsing_after_arrow (context_p); } case LEXER_KEYW_YIELD: @@ -1977,7 +1974,7 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ if (is_eval) { #if ENABLED (JERRY_ES2015) - if (context_p->status_flags & (PARSER_ALLOW_SUPER_CALL | PARSER_ALLOW_SUPER)) + if (context_p->status_flags & (PARSER_ALLOW_SUPER_CALL | PARSER_ALLOW_SUPER | PARSER_ALLOW_NEW_TARGET)) { parser_emit_cbc_ext_call (context_p, CBC_EXT_LOCAL_EVAL, diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index bf63d450c..16c13f406 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -65,26 +65,24 @@ typedef enum PARSER_DISALLOW_YIELD = (1u << 16), /**< throw SyntaxError for yield expression */ PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM = (1u << 17), /**< function has a non simple parameter */ PARSER_FUNCTION_HAS_REST_PARAM = (1u << 18), /**< function has rest parameter */ - /* These three status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */ + /* These 4 status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */ PARSER_CLASS_CONSTRUCTOR = (1u << 19), /**< a class constructor is parsed * Note: PARSER_ALLOW_SUPER must be present */ PARSER_ALLOW_SUPER = (1u << 20), /**< allow super property access */ PARSER_ALLOW_SUPER_CALL = (1u << 21), /**< allow super constructor call * Note: PARSER_CLASS_CONSTRUCTOR must be present */ + PARSER_ALLOW_NEW_TARGET = (1u << 22), /**< allow new.target parsing in the current context */ #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 22), /**< parsing a function or class default export */ - PARSER_MODULE_STORE_IDENT = (1u << 23), /**< store identifier of the current export statement */ + PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 23), /**< parsing a function or class default export */ + PARSER_MODULE_STORE_IDENT = (1u << 24), /**< store identifier of the current export statement */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ PARSER_HAS_LATE_LIT_INIT = (1u << 30), /**< there are identifier or string literals which construction * is postponed after the local parser data is freed */ #ifndef JERRY_NDEBUG PARSER_SCANNING_SUCCESSFUL = PARSER_HAS_LATE_LIT_INIT, /**< scanning process was successful */ #endif /* !JERRY_NDEBUG */ -#if ENABLED (JERRY_ES2015) - PARSER_ALLOW_NEW_TARGET = PARSER_IS_FUNCTION, /**< allow new.target parsing in the current context */ -#endif /* ENABLED (JERRY_ES2015) */ } parser_general_flags_t; /** @@ -137,7 +135,7 @@ typedef enum * Count of ecma_parse_opts_t class parsing options related bits */ #define PARSER_SAVED_FLAGS_COUNT \ - (JERRY_LOG2 (ECMA_PARSE_ALLOW_SUPER_CALL) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR) + 1) + (JERRY_LOG2 (ECMA_PARSE_ALLOW_NEW_TARGET) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR) + 1) /** * Mask for get class option bits from ecma_parse_opts_t diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 8a8312001..57085650f 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -2901,12 +2901,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ case LEXER_KEYW_RETURN: { - uint32_t status_flag = PARSER_IS_FUNCTION; -#if ENABLED (JERRY_ES2015) - status_flag |= PARSER_IS_ARROW_FUNCTION; -#endif /* ENABLED (JERRY_ES2015) */ - - if (!(context_p->status_flags & status_flag)) + if (!(context_p->status_flags & PARSER_IS_FUNCTION)) { parser_raise_error (context_p, PARSER_ERR_INVALID_RETURN); } diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 40e574eac..0b55643c5 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -2314,6 +2314,9 @@ parser_parse_function (parser_context_t *context_p, /**< context */ JERRY_ASSERT (status_flags & PARSER_IS_FUNCTION); parser_save_context (context_p, &saved_context); context_p->status_flags |= status_flags; +#if ENABLED (JERRY_ES2015) + context_p->status_flags |= PARSER_ALLOW_NEW_TARGET; +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) if (context_p->is_show_opcodes) @@ -2408,12 +2411,12 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */ parser_saved_context_t saved_context; ecma_compiled_code_t *compiled_code_p; - JERRY_ASSERT (!(status_flags & PARSER_IS_FUNCTION) - && (status_flags & PARSER_IS_ARROW_FUNCTION)); + JERRY_ASSERT (status_flags & PARSER_IS_FUNCTION); + JERRY_ASSERT (status_flags & PARSER_IS_ARROW_FUNCTION); parser_save_context (context_p, &saved_context); context_p->status_flags |= status_flags; #if ENABLED (JERRY_ES2015) - context_p->status_flags |= saved_context.status_flags & (PARSER_IS_FUNCTION + context_p->status_flags |= saved_context.status_flags & (PARSER_ALLOW_NEW_TARGET | PARSER_ALLOW_SUPER | PARSER_ALLOW_SUPER_CALL); #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 94889c559..dde5ce376 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -778,7 +778,6 @@ ecma_op_implicit_constructor_handler_cb (const ecma_value_t function_obj, /**< t return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); } - JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != JERRY_CONTEXT_INVALID_NEW_TARGET); return ECMA_VALUE_UNDEFINED; } /* ecma_op_implicit_constructor_handler_cb */ @@ -803,8 +802,6 @@ ecma_op_implicit_constructor_handler_heritage_cb (const ecma_value_t function_ob return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); } - JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != JERRY_CONTEXT_INVALID_NEW_TARGET); - ecma_object_t *func_obj_p = ecma_get_object_from_value (function_obj); ecma_value_t super_ctor = ecma_op_function_get_super_constructor (func_obj_p); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index e9e54ab32..cd225078c 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -1986,7 +1986,6 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { - JERRY_ASSERT (new_target_object != JERRY_CONTEXT_INVALID_NEW_TARGET); ecma_ref_object (new_target_object); *stack_top_p++ = ecma_make_object_value (new_target_object); } diff --git a/tests/jerry/es2015/regression-test-issue-3630.js b/tests/jerry/es2015/regression-test-issue-3630.js new file mode 100644 index 000000000..05f6e8b51 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3630.js @@ -0,0 +1,23 @@ +// 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. + +try { + { + class eval {} + eval() + } + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3640.js b/tests/jerry/es2015/regression-test-issue-3640.js new file mode 100644 index 000000000..1ac6dadb5 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3640.js @@ -0,0 +1,23 @@ +// 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. + +var B = class {} +eval = class extends B {} + +try { + eval(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} diff --git a/tests/jerry/es2015/regression-test-issue-3641.js b/tests/jerry/es2015/regression-test-issue-3641.js new file mode 100644 index 000000000..7f27579d8 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3641.js @@ -0,0 +1,26 @@ +// 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. + +eval = class extends SyntaxError { + constructor() { + super() + } +} + +try { + eval() + assert (false); +} catch (e) { + assert (e instanceof TypeError); +}