From 9b33fc8cbdfc2865e6d80dad568c5317c8bbaeec Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Tue, 10 Dec 2019 14:42:10 +0100 Subject: [PATCH] Revise the usage of the global error value/exception flag (#3426) This patch also fixes #3422. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- jerry-core/api/jerry-snapshot.c | 2 +- jerry-core/api/jerry.c | 2 +- jerry-core/debugger/debugger.c | 17 +--- jerry-core/debugger/debugger.h | 2 +- jerry-core/ecma/base/ecma-globals.h | 1 + jerry-core/ecma/base/ecma-helpers.c | 49 +++++---- jerry-core/ecma/base/ecma-helpers.h | 2 +- .../ecma-builtin-generator-prototype.c | 6 +- .../builtin-objects/ecma-builtin-promise.c | 5 +- .../builtin-objects/ecma-builtin-reflect.c | 18 +++- .../ecma-builtin-string-prototype.c | 6 +- jerry-core/ecma/operations/ecma-exceptions.c | 6 +- .../ecma/operations/ecma-function-object.c | 2 +- .../ecma/operations/ecma-iterator-object.c | 19 ++-- jerry-core/ecma/operations/ecma-jobqueue.c | 6 +- jerry-core/ecma/operations/ecma-objects.c | 2 +- .../ecma/operations/ecma-promise-object.c | 6 +- .../ecma/operations/ecma-typedarray-object.c | 2 +- jerry-core/jcontext/jcontext.c | 99 +++++++++++++++++++ jerry-core/jcontext/jcontext.h | 22 +++++ jerry-core/parser/js/js-lexer.c | 10 +- jerry-core/parser/js/js-parser.c | 3 +- jerry-core/parser/regexp/re-parser.c | 4 +- jerry-core/vm/opcodes.c | 2 +- jerry-core/vm/vm.c | 33 +++---- .../es2015/regression-test-issue-3422.js | 16 +++ tests/unit-core/test-to-integer.c | 2 +- tests/unit-core/test-to-length.c | 2 +- 28 files changed, 238 insertions(+), 108 deletions(-) create mode 100644 tests/jerry/es2015/regression-test-issue-3422.js diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index 952b56d8a..f547b161d 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -763,7 +763,7 @@ jerry_generate_snapshot_with_args (const jerry_char_t *resource_name_p, /**< scr if (ECMA_IS_VALUE_ERROR (parse_status)) { - return ecma_create_error_reference (JERRY_CONTEXT (error_value), true); + return ecma_create_error_reference_from_context (); } JERRY_ASSERT (bytecode_data_p != NULL); diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 068a07603..49bd4a648 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -3057,7 +3057,7 @@ jerry_foreach_object_property (const jerry_value_t obj_val, /**< object value */ return true; } - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); return false; } /* jerry_foreach_object_property */ diff --git a/jerry-core/debugger/debugger.c b/jerry-core/debugger/debugger.c index 809d9adf3..f3b207f6d 100644 --- a/jerry-core/debugger/debugger.c +++ b/jerry-core/debugger/debugger.c @@ -555,21 +555,15 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s { if (eval_string_p[4] != JERRY_DEBUGGER_EVAL_EVAL) { + JERRY_ASSERT (eval_string_p[4] == JERRY_DEBUGGER_EVAL_THROW || eval_string_p[4] == JERRY_DEBUGGER_EVAL_ABORT); JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); - JERRY_CONTEXT (error_value) = result; /* Stop where the error is caught. */ JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; - if (eval_string_p[4] == JERRY_DEBUGGER_EVAL_THROW) - { - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; - } - else - { - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; - } + jcontext_raise_exception (result); + jcontext_set_abort_flag (eval_string_p[4] == JERRY_DEBUGGER_EVAL_ABORT); return true; } @@ -1519,12 +1513,11 @@ jerry_debugger_exception_object_to_string (ecma_value_t exception_obj_value) /** * false - otherwise */ bool -jerry_debugger_send_exception_string (void) +jerry_debugger_send_exception_string (ecma_value_t exception_value) { + JERRY_ASSERT (jcontext_has_pending_exception ()); ecma_string_t *string_p = NULL; - ecma_value_t exception_value = JERRY_CONTEXT (error_value); - if (ecma_is_value_object (exception_value)) { string_p = jerry_debugger_exception_object_to_string (exception_value); diff --git a/jerry-core/debugger/debugger.h b/jerry-core/debugger/debugger.h index 4324551f6..b940eeeeb 100644 --- a/jerry-core/debugger/debugger.h +++ b/jerry-core/debugger/debugger.h @@ -484,7 +484,7 @@ bool jerry_debugger_send_string (uint8_t message_type, uint8_t sub_type, const u bool jerry_debugger_send_function_cp (jerry_debugger_header_type_t type, ecma_compiled_code_t *compiled_code_p); bool jerry_debugger_send_parse_function (uint32_t line, uint32_t column); void jerry_debugger_send_memstats (void); -bool jerry_debugger_send_exception_string (void); +bool jerry_debugger_send_exception_string (ecma_value_t exception_value); #endif /* ENABLED (JERRY_DEBUGGER) */ diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 8d75a315b..63087ea88 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -62,6 +62,7 @@ typedef enum 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_ABORT = (1u << 4), /**< last exception is an abort */ } ecma_status_flag_t; /** diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 1f0d4e72d..5212484f8 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -1256,7 +1256,6 @@ ecma_create_error_reference (ecma_value_t value, /**< referenced value */ { ecma_error_reference_t *error_ref_p = (ecma_error_reference_t *) jmem_pools_alloc (sizeof (ecma_error_reference_t)); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; error_ref_p->refs_and_flags = ECMA_ERROR_REF_ONE | (is_exception ? 0 : ECMA_ERROR_REF_ABORT); error_ref_p->value = value; return ecma_make_error_reference_value (error_ref_p); @@ -1270,8 +1269,13 @@ ecma_create_error_reference (ecma_value_t value, /**< referenced value */ ecma_value_t ecma_create_error_reference_from_context (void) { - return ecma_create_error_reference (JERRY_CONTEXT (error_value), - (JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION) != 0); + bool is_abort = jcontext_has_pending_abort (); + + if (is_abort) + { + jcontext_set_abort_flag (false); + } + return ecma_create_error_reference (jcontext_take_exception (), !is_abort); } /* ecma_create_error_reference_from_context */ /** @@ -1322,40 +1326,35 @@ ecma_deref_error_reference (ecma_error_reference_t *error_ref_p) /**< error refe } /* ecma_deref_error_reference */ /** - * Clears error reference, and returns with the value. + * Raise error from the given error reference. * - * @return value referenced by the error + * Note: the error reference's ref count is also decreased */ -ecma_value_t -ecma_clear_error_reference (ecma_value_t value, /**< error reference */ - bool set_abort_flag) /**< set abort flag */ +void +ecma_raise_error_from_error_reference (ecma_value_t value) /**< error reference */ { + JERRY_ASSERT (!jcontext_has_pending_exception () && !jcontext_has_pending_abort ()); ecma_error_reference_t *error_ref_p = ecma_get_error_reference_from_value (value); - if (set_abort_flag) - { - if (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT) - { - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; - } - else - { - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; - } - } - JERRY_ASSERT (error_ref_p->refs_and_flags >= ECMA_ERROR_REF_ONE); + ecma_value_t referenced_value = error_ref_p->value; + + jcontext_set_exception_flag (true); + jcontext_set_abort_flag (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT); + if (error_ref_p->refs_and_flags >= 2 * ECMA_ERROR_REF_ONE) { error_ref_p->refs_and_flags -= ECMA_ERROR_REF_ONE; - return ecma_copy_value (error_ref_p->value); + referenced_value = ecma_copy_value (referenced_value); + } + else + { + jmem_pools_free (error_ref_p, sizeof (ecma_error_reference_t)); } - ecma_value_t referenced_value = error_ref_p->value; - jmem_pools_free (error_ref_p, sizeof (ecma_error_reference_t)); - return referenced_value; -} /* ecma_clear_error_reference */ + JERRY_CONTEXT (error_value) = referenced_value; +} /* ecma_raise_error_from_error_reference */ /** * Increase reference counter of Compact diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 0e7e755fd..f5801eedf 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -421,7 +421,7 @@ ecma_value_t ecma_create_error_reference_from_context (void); ecma_value_t ecma_create_error_object_reference (ecma_object_t *object_p); void ecma_ref_error_reference (ecma_error_reference_t *error_ref_p); void ecma_deref_error_reference (ecma_error_reference_t *error_ref_p); -ecma_value_t ecma_clear_error_reference (ecma_value_t value, bool set_abort_flag); +void ecma_raise_error_from_error_reference (ecma_value_t value); void ecma_bytecode_ref (ecma_compiled_code_t *bytecode_p); void ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c index 44277709d..d59a874c8 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c @@ -137,8 +137,7 @@ ecma_builtin_generator_prototype_object_do (ecma_value_t this_arg, /**< this arg if (ECMA_IS_VALUE_ERROR (arg)) { - arg = JERRY_CONTEXT (error_value); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + arg = jcontext_take_exception (); resume_mode = ECMA_ITERATOR_THROW; } } @@ -176,8 +175,7 @@ ecma_builtin_generator_prototype_object_do (ecma_value_t this_arg, /**< this arg if (ECMA_IS_VALUE_ERROR (iterator)) { resume_mode = ECMA_ITERATOR_THROW; - arg = JERRY_CONTEXT (error_value); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + arg = jcontext_take_exception (); continue; } diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c index 23e7c249e..5e1f0937a 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c @@ -127,8 +127,7 @@ inline static ecma_value_t ecma_builtin_promise_reject_abrupt (ecma_value_t capability) /**< reject description */ { ecma_raise_type_error (ECMA_ERR_MSG ("Second argument is not an array.")); - ecma_value_t reason = JERRY_CONTEXT (error_value); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + ecma_value_t reason = jcontext_take_exception (); ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p); @@ -610,7 +609,7 @@ ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */ if (ECMA_IS_VALUE_ERROR (ret)) { - ret = JERRY_CONTEXT (error_value); + ret = jcontext_take_exception (); } ecma_free_value (capability); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c index 578bb253a..07127cb0a 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c @@ -93,7 +93,14 @@ ecma_builtin_reflect_dispatch_routine (uint16_t builtin_routine_id, /**< built-i ecma_value_t result = ecma_builtin_object_object_set_prototype_of (arguments_list[0], arguments_list[1]); bool is_error = ECMA_IS_VALUE_ERROR (result); - ecma_free_value (is_error ? JERRY_CONTEXT (error_value) : result); + if (is_error) + { + jcontext_release_exception (); + } + else + { + ecma_free_value (result); + } return ecma_make_boolean_value (!is_error); } @@ -121,7 +128,14 @@ ecma_builtin_reflect_dispatch_routine (uint16_t builtin_routine_id, /**< built-i ecma_deref_ecma_string (name_str_p); bool is_error = ECMA_IS_VALUE_ERROR (result); - ecma_free_value (is_error ? JERRY_CONTEXT (error_value) : result); + if (is_error) + { + jcontext_release_exception (); + } + else + { + ecma_free_value (result); + } return ecma_make_boolean_value (!is_error); } diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c index e2629ad11..2bcf72288 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c @@ -808,8 +808,7 @@ ecma_builtin_string_prototype_object_split (ecma_value_t this_to_string_val, /** if (ECMA_IS_VALUE_ERROR (match_result)) { - match_result = JERRY_CONTEXT (error_value); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + match_result = jcontext_take_exception (); } ecma_free_value (match_result); @@ -898,8 +897,7 @@ ecma_builtin_string_prototype_object_split (ecma_value_t this_to_string_val, /** curr_pos++; if (ECMA_IS_VALUE_ERROR (match_result)) { - ecma_free_value (JERRY_CONTEXT (error_value)); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + jcontext_release_exception (); } } else diff --git a/jerry-core/ecma/operations/ecma-exceptions.c b/jerry-core/ecma/operations/ecma-exceptions.c index 54ed8b575..43697a297 100644 --- a/jerry-core/ecma/operations/ecma-exceptions.c +++ b/jerry-core/ecma/operations/ecma-exceptions.c @@ -238,8 +238,7 @@ ecma_raise_standard_error (ecma_standard_error_t error_type, /**< error type */ error_obj_p = ecma_new_standard_error (error_type); } - JERRY_CONTEXT (error_value) = ecma_make_object_value (error_obj_p); - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (ecma_make_object_value (error_obj_p)); return ECMA_VALUE_ERROR; } /* ecma_raise_standard_error */ @@ -333,8 +332,7 @@ ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, /**< er ecma_object_t *error_obj_p = ecma_new_standard_error_with_message (error_type, error_msg_p); ecma_deref_ecma_string (error_msg_p); - JERRY_CONTEXT (error_value) = ecma_make_object_value (error_obj_p); - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (ecma_make_object_value (error_obj_p)); return ECMA_VALUE_ERROR; } /* ecma_raise_standard_error_with_format */ diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 9fc16d5d2..d4a1dad29 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -880,7 +880,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ if (JERRY_UNLIKELY (ecma_is_value_error_reference (ret_value))) { - JERRY_CONTEXT (error_value) = ecma_clear_error_reference (ret_value, true); + ecma_raise_error_from_error_reference (ret_value); return ECMA_VALUE_ERROR; } diff --git a/jerry-core/ecma/operations/ecma-iterator-object.c b/jerry-core/ecma/operations/ecma-iterator-object.c index 3b4709c04..ceffa652e 100644 --- a/jerry-core/ecma/operations/ecma-iterator-object.c +++ b/jerry-core/ecma/operations/ecma-iterator-object.c @@ -416,10 +416,9 @@ ecma_op_iterator_close (ecma_value_t iterator) /**< iterator value */ /* 2. */ ecma_value_t completion = ECMA_VALUE_EMPTY; - if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION) + if (jcontext_has_pending_exception ()) { - completion = JERRY_CONTEXT (error_value); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + completion = jcontext_take_exception (); } /* 3. */ @@ -440,7 +439,7 @@ ecma_op_iterator_close (ecma_value_t iterator) /**< iterator value */ return ECMA_VALUE_UNDEFINED; } - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (completion); return ECMA_VALUE_ERROR; } @@ -454,12 +453,14 @@ ecma_op_iterator_close (ecma_value_t iterator) /**< iterator value */ { if (ECMA_IS_VALUE_ERROR (inner_result)) { - ecma_free_value (JERRY_CONTEXT (error_value)); - JERRY_CONTEXT (error_value) = completion; + jcontext_release_exception (); + } + else + { + ecma_free_value (inner_result); } - ecma_free_value (inner_result); - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (completion); return ECMA_VALUE_ERROR; } @@ -486,7 +487,7 @@ ecma_op_iterator_close (ecma_value_t iterator) /**< iterator value */ return ECMA_VALUE_UNDEFINED; } - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (completion); return ECMA_VALUE_ERROR; } /* ecma_op_iterator_close */ diff --git a/jerry-core/ecma/operations/ecma-jobqueue.c b/jerry-core/ecma/operations/ecma-jobqueue.c index 5a04cca64..30dcb5b70 100644 --- a/jerry-core/ecma/operations/ecma-jobqueue.c +++ b/jerry-core/ecma/operations/ecma-jobqueue.c @@ -179,8 +179,7 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ { if (ECMA_IS_VALUE_ERROR (handler_result)) { - handler_result = JERRY_CONTEXT (error_value); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + handler_result = jcontext_take_exception (); } /* 7. */ @@ -254,8 +253,7 @@ ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be opera if (ECMA_IS_VALUE_ERROR (then_call_result)) { - then_call_result = JERRY_CONTEXT (error_value); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + then_call_result = jcontext_take_exception (); ret = ecma_op_function_call (ecma_get_object_from_value (funcs->reject), ECMA_VALUE_UNDEFINED, diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 9205ee9c3..1103ba10d 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -1232,7 +1232,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ if (ECMA_IS_VALUE_ERROR (error)) { - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); return ecma_reject (is_throw); } diff --git a/jerry-core/ecma/operations/ecma-promise-object.c b/jerry-core/ecma/operations/ecma-promise-object.c index b4048789f..88258efc7 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.c +++ b/jerry-core/ecma/operations/ecma-promise-object.c @@ -330,8 +330,7 @@ ecma_promise_resolve_handler (const ecma_value_t function, /**< the function its if (ECMA_IS_VALUE_ERROR (then)) { /* 9. */ - then = JERRY_CONTEXT (error_value); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + then = jcontext_take_exception (); ecma_reject_promise (promise, then); } else if (!ecma_op_is_callable (then)) @@ -551,8 +550,7 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function if (ECMA_IS_VALUE_ERROR (completion)) { /* 10.a. */ - completion = JERRY_CONTEXT (error_value); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + completion = jcontext_take_exception (); status = ecma_op_function_call (ecma_get_object_from_value (funcs->reject), ECMA_VALUE_UNDEFINED, &completion, diff --git a/jerry-core/ecma/operations/ecma-typedarray-object.c b/jerry-core/ecma/operations/ecma-typedarray-object.c index 6568e135d..715663283 100644 --- a/jerry-core/ecma/operations/ecma-typedarray-object.c +++ b/jerry-core/ecma/operations/ecma-typedarray-object.c @@ -1130,7 +1130,7 @@ ecma_op_typedarray_define_index_prop (ecma_object_t *obj_p, /**< a TypedArray ob if (ECMA_IS_VALUE_ERROR (error)) { - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); return false; } ecma_typedarray_info_t info = ecma_typedarray_get_info (obj_p); diff --git a/jerry-core/jcontext/jcontext.c b/jerry-core/jcontext/jcontext.c index daac40498..37f0fe69b 100644 --- a/jerry-core/jcontext/jcontext.c +++ b/jerry-core/jcontext/jcontext.c @@ -19,6 +19,105 @@ * @{ */ +/** + * Check the existence of the ECMA_STATUS_EXCEPTION flag. + * + * @return true - if the flag is set + * false - otherwise + */ +extern inline bool JERRY_ATTR_ALWAYS_INLINE +jcontext_has_pending_exception (void) +{ + return JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION; +} /* jcontext_has_pending_exception */ + +/** + * Check the existence of the ECMA_STATUS_ABORT flag. + * + * @return true - if the flag is set + * false - otherwise + */ +extern inline bool JERRY_ATTR_ALWAYS_INLINE +jcontext_has_pending_abort (void) +{ + return JERRY_CONTEXT (status_flags) & ECMA_STATUS_ABORT; +} /* jcontext_has_pending_abort */ + +/** + * Set the abort flag for the context. + */ +extern inline void JERRY_ATTR_ALWAYS_INLINE +jcontext_set_abort_flag (bool is_abort) /**< true - if the abort flag should be set + * false - if the abort flag should be removed */ +{ + JERRY_ASSERT (jcontext_has_pending_exception ()); + + if (is_abort) + { + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_ABORT; + } + else + { + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_ABORT; + } +} /* jcontext_set_abort_flag */ + +/** + * Set the exception flag for the context. + */ +extern inline void JERRY_ATTR_ALWAYS_INLINE +jcontext_set_exception_flag (bool is_exception) /**< true - if the exception flag should be set + * false - if the exception flag should be removed */ +{ + if (is_exception) + { + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + } + else + { + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + } +} /* jcontext_set_exception_flag */ + +/** + * Raise exception from the given error value. + */ +extern inline void JERRY_ATTR_ALWAYS_INLINE +jcontext_raise_exception (ecma_value_t error) /**< error to raise */ +{ + JERRY_ASSERT (!jcontext_has_pending_exception ()); + JERRY_ASSERT (!jcontext_has_pending_abort ()); + + JERRY_CONTEXT (error_value) = error; + jcontext_set_exception_flag (true); +} /* jcontext_raise_exception */ + +/** + * Release the current exception/abort of the context. + */ +void +jcontext_release_exception (void) +{ + JERRY_ASSERT (jcontext_has_pending_exception ()); + + ecma_free_value (jcontext_take_exception ()); +} /* jcontext_release_exception */ + +/** + * Take the current exception/abort of context. + * + * @return current exception as an ecma-value + */ +ecma_value_t +jcontext_take_exception (void) +{ + JERRY_ASSERT (jcontext_has_pending_exception ()); + + jcontext_set_abort_flag (false); + jcontext_set_exception_flag (false); + return JERRY_CONTEXT (error_value); +} /* jcontext_take_exception */ + #if !ENABLED (JERRY_EXTERNAL_CONTEXT) /** diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index b974ecf66..b8475fd74 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -21,6 +21,7 @@ #include "debugger.h" #include "ecma-builtins.h" +#include "ecma-helpers.h" #include "ecma-jobqueue.h" #include "jerryscript-port.h" #include "jmem.h" @@ -294,6 +295,27 @@ extern jmem_heap_t jerry_global_heap; #endif /* ENABLED (JERRY_EXTERNAL_CONTEXT) */ +void +jcontext_set_exception_flag (bool is_exception); + +void +jcontext_set_abort_flag (bool is_abort); + +bool +jcontext_has_pending_exception (void); + +bool +jcontext_has_pending_abort (void); + +void +jcontext_raise_exception (ecma_value_t error); + +void +jcontext_release_exception (void); + +ecma_value_t +jcontext_take_exception (void); + /** * @} */ diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index f54bb1d26..d46bf3664 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -2433,16 +2433,14 @@ lexer_construct_regexp_object (parser_context_t *context_p, /**< context */ current_flags); ecma_deref_ecma_string (pattern_str_p); - bool is_throw = ECMA_IS_VALUE_ERROR (completion_value) != 0; - - ecma_free_value (completion_value); - - if (is_throw) + if (ECMA_IS_VALUE_ERROR (completion_value)) { - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); parser_raise_error (context_p, PARSER_ERR_INVALID_REGEXP); } + ecma_free_value (completion_value); + literal_p->type = LEXER_REGEXP_LITERAL; literal_p->u.bytecode_p = (ecma_compiled_code_t *) re_bytecode_p; diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index ffee4613b..1ecd49953 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -2542,8 +2542,7 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */ { /* It is unlikely that memory can be allocated in an out-of-memory * situation. However, a simple value can still be thrown. */ - JERRY_CONTEXT (error_value) = ECMA_VALUE_NULL; - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (ECMA_VALUE_NULL); return ECMA_VALUE_ERROR; } #if ENABLED (JERRY_ERROR_MESSAGES) diff --git a/jerry-core/parser/regexp/re-parser.c b/jerry-core/parser/regexp/re-parser.c index 32a2fd2a2..981aa0c0d 100644 --- a/jerry-core/parser/regexp/re-parser.c +++ b/jerry-core/parser/regexp/re-parser.c @@ -656,7 +656,7 @@ re_parse_next_token (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context * } JERRY_ASSERT (ECMA_IS_VALUE_ERROR (ret_value)); - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); parser_ctx_p->input_curr_p = input_curr_p; /* It was not an iterator, continue the parsing. */ @@ -682,7 +682,7 @@ re_parse_next_token (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context * if (!ecma_is_value_empty (ret_value)) { - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); parser_ctx_p->input_curr_p = input_curr_p; ret_value = ECMA_VALUE_EMPTY; } diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 37d2b31c2..2550a505e 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -84,7 +84,7 @@ vm_set_var (ecma_object_t *lex_env_p, /**< target lexical environment */ if (ECMA_IS_VALUE_ERROR (put_value_result)) { - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); } ecma_free_value (lit_value); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index a137360b6..dab16304e 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -169,7 +169,7 @@ vm_op_set_value (ecma_value_t object, /**< base object */ { #if ENABLED (JERRY_ERROR_MESSAGES) ecma_free_value (to_object); - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); ecma_value_t error_value = ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE, "Cannot set property '%' of %", @@ -1273,16 +1273,17 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { JERRY_CONTEXT (vm_exec_stop_counter) = 1; - if (!ecma_is_value_error_reference (result)) + if (ecma_is_value_error_reference (result)) { - JERRY_CONTEXT (error_value) = result; + ecma_raise_error_from_error_reference (result); } else { - JERRY_CONTEXT (error_value) = ecma_clear_error_reference (result, false); + jcontext_raise_exception (result); } - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + JERRY_ASSERT (jcontext_has_pending_exception ()); + jcontext_set_abort_flag (true); result = ECMA_VALUE_ERROR; goto error; } @@ -1628,7 +1629,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { if (ECMA_IS_VALUE_ERROR (result)) { - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); } ecma_free_value (result); @@ -2415,8 +2416,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_THROW: { - JERRY_CONTEXT (error_value) = left_value; - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (left_value); result = ECMA_VALUE_ERROR; left_value = ECMA_VALUE_UNDEFINED; @@ -2636,8 +2636,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ if (ref_base_lex_env_p == NULL) { - ecma_free_value (JERRY_CONTEXT (error_value)); - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + jcontext_release_exception (); result = ECMA_VALUE_UNDEFINED; } else if (ECMA_IS_VALUE_ERROR (result)) @@ -3578,8 +3577,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ if (context_type == VM_CONTEXT_FINALLY_THROW) { - JERRY_CONTEXT (error_value) = *stack_top_p; - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + jcontext_raise_exception (*stack_top_p); result = ECMA_VALUE_ERROR; #if ENABLED (JERRY_DEBUGGER) @@ -3841,6 +3839,7 @@ error: if (ECMA_IS_VALUE_ERROR (result)) { + JERRY_ASSERT (jcontext_has_pending_exception ()); ecma_value_t *stack_bottom_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth; while (stack_top_p > stack_bottom_p) @@ -3862,7 +3861,7 @@ error: therefore an evaluation error, or user-created error throw would overwrite it. */ ecma_value_t current_error_value = JERRY_CONTEXT (error_value); - if (jerry_debugger_send_exception_string ()) + if (jerry_debugger_send_exception_string (current_error_value)) { jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_EXCEPTION_HIT); @@ -3907,7 +3906,7 @@ error: continue; } } - else if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION) + else if (jcontext_has_pending_exception () && !jcontext_has_pending_abort ()) { if (vm_stack_find_finally (frame_ctx_p, &stack_top_p, @@ -3921,19 +3920,19 @@ error: JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); #endif /* ENABLED (JERRY_DEBUGGER) */ - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + result = jcontext_take_exception (); byte_code_p = frame_ctx_p->byte_code_p; if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FINALLY_THROW) { - stack_top_p[-2] = JERRY_CONTEXT (error_value); + stack_top_p[-2] = result; continue; } JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH); - *stack_top_p++ = JERRY_CONTEXT (error_value); + *stack_top_p++ = result; continue; } } diff --git a/tests/jerry/es2015/regression-test-issue-3422.js b/tests/jerry/es2015/regression-test-issue-3422.js new file mode 100644 index 000000000..d93f23ff8 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3422.js @@ -0,0 +1,16 @@ +// 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. + +assert (typeof RegExp('{}') === "object"); +let {t: []} = {t: []}; diff --git a/tests/unit-core/test-to-integer.c b/tests/unit-core/test-to-integer.c index 191e0d53e..37097f2d9 100644 --- a/tests/unit-core/test-to-integer.c +++ b/tests/unit-core/test-to-integer.c @@ -51,7 +51,7 @@ main (void) result = ecma_op_to_integer (error, &num); - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); TEST_ASSERT (ECMA_IS_VALUE_ERROR (result)); diff --git a/tests/unit-core/test-to-length.c b/tests/unit-core/test-to-length.c index 4c6c2976c..af967991a 100644 --- a/tests/unit-core/test-to-length.c +++ b/tests/unit-core/test-to-length.c @@ -51,7 +51,7 @@ main (void) result = ecma_op_to_length (error_throw, &num); - ecma_free_value (JERRY_CONTEXT (error_value)); + jcontext_release_exception (); TEST_ASSERT (ECMA_IS_VALUE_ERROR (result));