diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array.c index 5f97712b2..c7371b5ca 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array.c @@ -153,7 +153,7 @@ ecma_builtin_array_object_from (ecma_value_t this_arg, /**< 'this' argument */ ecma_object_t *array_obj_p = ecma_get_object_from_value (array); /* 6.d */ - ecma_value_t iterator = ecma_op_get_iterator (items, using_iterator); + ecma_value_t iterator = ecma_op_get_iterator (items, using_iterator, NULL); ecma_free_value (using_iterator); /* 6.e */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-async-generator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-async-generator-prototype.c index 1f0ac4062..61de3e49a 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-async-generator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-async-generator-prototype.c @@ -46,6 +46,20 @@ enum ECMA_ASYNC_GENERATOR_PROTOTYPE_ROUTINE_RETURN }; +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-async-generator-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID async_generator_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup asyncgenerator ECMA AsyncGenerator.prototype object built-in + * @{ + */ + /** * Convert routine type to operation type.. */ @@ -64,20 +78,6 @@ JERRY_STATIC_ASSERT (ECMA_ASYNC_GENERATOR_ROUTINE_TO_OPERATION (ECMA_ASYNC_GENER == ECMA_ASYNC_GENERATOR_DO_RETURN, convert_ecma_async_generator_routine_return_to_ecma_async_generator_do_return_failed); -#define BUILTIN_INC_HEADER_NAME "ecma-builtin-async-generator-prototype.inc.h" -#define BUILTIN_UNDERSCORED_ID async_generator_prototype -#include "ecma-builtin-internal-routines-template.inc.h" - -/** \addtogroup ecma ECMA - * @{ - * - * \addtogroup ecmabuiltins - * @{ - * - * \addtogroup asyncgenerator ECMA AsyncGenerator.prototype object built-in - * @{ - */ - /** * Dispatcher of the Generator built-in's routines * 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 2db82969c..6db7e7a5c 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c @@ -42,7 +42,7 @@ enum ECMA_GENERATOR_PROTOTYPE_ROUTINE_NEXT, ECMA_GENERATOR_PROTOTYPE_ROUTINE_THROW, ECMA_GENERATOR_PROTOTYPE_ROUTINE_RETURN -}; +} ecma_generator_operation_type_t; #define BUILTIN_INC_HEADER_NAME "ecma-builtin-generator-prototype.inc.h" #define BUILTIN_UNDERSCORED_ID generator_prototype @@ -58,6 +58,24 @@ enum * @{ */ +/** + * Convert routine type to operation type.. + */ +#define ECMA_GENERATOR_ROUTINE_TO_OPERATION(type) \ + ((ecma_iterator_command_type_t) ((type) - ECMA_GENERATOR_PROTOTYPE_ROUTINE_NEXT)) + +JERRY_STATIC_ASSERT (ECMA_GENERATOR_ROUTINE_TO_OPERATION (ECMA_GENERATOR_PROTOTYPE_ROUTINE_NEXT) + == ECMA_ITERATOR_NEXT, + convert_ecma_generator_routine_next_to_ecma_iterator_next_failed); + +JERRY_STATIC_ASSERT (ECMA_GENERATOR_ROUTINE_TO_OPERATION (ECMA_GENERATOR_PROTOTYPE_ROUTINE_THROW) + == ECMA_ITERATOR_THROW, + convert_ecma_generator_routine_throw_to_ecma_iterator_throw_failed); + +JERRY_STATIC_ASSERT (ECMA_GENERATOR_ROUTINE_TO_OPERATION (ECMA_GENERATOR_PROTOTYPE_ROUTINE_RETURN) + == ECMA_ITERATOR_RETURN, + convert_ecma_generator_routine_return_to_ecma_iterator_return_failed); + /** * Helper function for next / return / throw * @@ -65,7 +83,7 @@ enum * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_generator_prototype_object_do (vm_executable_object_t *executable_object_p, /**< executable object */ +ecma_builtin_generator_prototype_object_do (vm_executable_object_t *generator_object_p, /**< generator object */ ecma_value_t arg, /**< argument */ ecma_iterator_command_type_t resume_mode) /**< resume mode */ { @@ -73,12 +91,13 @@ ecma_builtin_generator_prototype_object_do (vm_executable_object_t *executable_o while (true) { - if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_GENERATOR_ITERATE_AND_YIELD) + if (generator_object_p->extended_object.u.class_prop.extra_info & ECMA_GENERATOR_ITERATE_AND_YIELD) { - ecma_value_t iterator = executable_object_p->frame_ctx.block_result; + ecma_value_t iterator = generator_object_p->frame_ctx.block_result; + ecma_value_t next_method = generator_object_p->frame_ctx.stack_top_p[-1]; bool done = false; - ecma_value_t result = ecma_op_iterator_do (resume_mode, iterator, arg, &done); + ecma_value_t result = ecma_op_iterator_do (resume_mode, iterator, next_method, arg, &done); ecma_free_value (arg); if (ECMA_IS_VALUE_ERROR (result)) @@ -89,10 +108,9 @@ ecma_builtin_generator_prototype_object_do (vm_executable_object_t *executable_o { arg = ecma_op_iterator_value (result); ecma_free_value (result); + if (resume_mode == ECMA_ITERATOR_THROW) { - /* This part is changed in the newest ECMAScript standard. - * It was ECMA_ITERATOR_RETURN in ES2015, but I think it was a typo. */ resume_mode = ECMA_ITERATOR_NEXT; } } @@ -101,8 +119,12 @@ ecma_builtin_generator_prototype_object_do (vm_executable_object_t *executable_o return result; } - executable_object_p->extended_object.u.class_prop.extra_info &= (uint16_t) ~ECMA_GENERATOR_ITERATE_AND_YIELD; - executable_object_p->frame_ctx.block_result = ECMA_VALUE_UNDEFINED; + generator_object_p->extended_object.u.class_prop.extra_info &= (uint16_t) ~ECMA_GENERATOR_ITERATE_AND_YIELD; + generator_object_p->frame_ctx.block_result = ECMA_VALUE_UNDEFINED; + + JERRY_ASSERT (generator_object_p->frame_ctx.stack_top_p[-1] == ECMA_VALUE_UNDEFINED + || ecma_is_value_object (generator_object_p->frame_ctx.stack_top_p[-1])); + generator_object_p->frame_ctx.stack_top_p--; if (ECMA_IS_VALUE_ERROR (arg)) { @@ -113,32 +135,34 @@ ecma_builtin_generator_prototype_object_do (vm_executable_object_t *executable_o if (resume_mode == ECMA_ITERATOR_RETURN) { - executable_object_p->frame_ctx.byte_code_p = opfunc_resume_executable_object_with_return; + generator_object_p->frame_ctx.byte_code_p = opfunc_resume_executable_object_with_return; } else if (resume_mode == ECMA_ITERATOR_THROW) { - executable_object_p->frame_ctx.byte_code_p = opfunc_resume_executable_object_with_throw; + generator_object_p->frame_ctx.byte_code_p = opfunc_resume_executable_object_with_throw; } - ecma_value_t value = opfunc_resume_executable_object (executable_object_p, arg); + ecma_value_t value = opfunc_resume_executable_object (generator_object_p, arg); if (ECMA_IS_VALUE_ERROR (value)) { return value; } - bool done = (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED); + bool done = (generator_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED); if (!done) { - const uint8_t *byte_code_p = executable_object_p->frame_ctx.byte_code_p; + const uint8_t *byte_code_p = generator_object_p->frame_ctx.byte_code_p; JERRY_ASSERT (byte_code_p[-2] == CBC_EXT_OPCODE && (byte_code_p[-1] == CBC_EXT_YIELD || byte_code_p[-1] == CBC_EXT_YIELD_ITERATOR)); if (byte_code_p[-1] == CBC_EXT_YIELD_ITERATOR) { - ecma_value_t iterator = ecma_op_get_iterator (value, ECMA_VALUE_SYNC_ITERATOR); + ecma_value_t iterator = ecma_op_get_iterator (value, + ECMA_VALUE_SYNC_ITERATOR, + generator_object_p->frame_ctx.stack_top_p); ecma_free_value (value); if (ECMA_IS_VALUE_ERROR (iterator)) @@ -149,8 +173,15 @@ ecma_builtin_generator_prototype_object_do (vm_executable_object_t *executable_o } ecma_deref_object (ecma_get_object_from_value (iterator)); - executable_object_p->extended_object.u.class_prop.extra_info |= ECMA_GENERATOR_ITERATE_AND_YIELD; - executable_object_p->frame_ctx.block_result = iterator; + generator_object_p->extended_object.u.class_prop.extra_info |= ECMA_GENERATOR_ITERATE_AND_YIELD; + generator_object_p->frame_ctx.block_result = iterator; + + if (generator_object_p->frame_ctx.stack_top_p[0] != ECMA_VALUE_UNDEFINED) + { + ecma_deref_object (ecma_get_object_from_value (generator_object_p->frame_ctx.stack_top_p[0])); + } + + generator_object_p->frame_ctx.stack_top_p++; arg = ECMA_VALUE_UNDEFINED; continue; } @@ -216,30 +247,9 @@ ecma_builtin_generator_prototype_dispatch_routine (uint16_t builtin_routine_id, return ECMA_VALUE_ERROR; } - switch (builtin_routine_id) - { - case ECMA_GENERATOR_PROTOTYPE_ROUTINE_NEXT: - { - return ecma_builtin_generator_prototype_object_do (executable_object_p, - arguments_list_p[0], - ECMA_ITERATOR_NEXT); - } - case ECMA_GENERATOR_PROTOTYPE_ROUTINE_THROW: - { - return ecma_builtin_generator_prototype_object_do (executable_object_p, - arguments_list_p[0], - ECMA_ITERATOR_THROW); - } - default: - { - JERRY_ASSERT (builtin_routine_id == ECMA_GENERATOR_PROTOTYPE_ROUTINE_RETURN); - return ecma_builtin_generator_prototype_object_do (executable_object_p, - arguments_list_p[0], - ECMA_ITERATOR_RETURN); - } - } - - return ECMA_VALUE_EMPTY; + return ecma_builtin_generator_prototype_object_do (executable_object_p, + arguments_list_p[0], + ECMA_GENERATOR_ROUTINE_TO_OPERATION (builtin_routine_id)); } /* ecma_builtin_generator_prototype_dispatch_routine */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c index 33b489e8b..3c032a2ca 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c @@ -528,7 +528,7 @@ ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */ } ecma_value_t iterator; - iterator = ecma_builtin_promise_reject_abrupt (ecma_op_get_iterator (iterable, ECMA_VALUE_SYNC_ITERATOR), + iterator = ecma_builtin_promise_reject_abrupt (ecma_op_get_iterator (iterable, ECMA_VALUE_SYNC_ITERATOR, NULL), capability); if (ECMA_IS_VALUE_ERROR (iterator)) diff --git a/jerry-core/ecma/operations/ecma-async-generator-object.c b/jerry-core/ecma/operations/ecma-async-generator-object.c index b9884701d..87f1ff519 100644 --- a/jerry-core/ecma/operations/ecma-async-generator-object.c +++ b/jerry-core/ecma/operations/ecma-async-generator-object.c @@ -203,7 +203,9 @@ ecma_async_generator_run (vm_executable_object_t *async_generator_object_p) /**< { case ECMA_ASYNC_GENERATOR_DO_NEXT: { - result = ecma_op_iterator_next (async_generator_object_p->frame_ctx.block_result, task_p->operation_value); + result = ecma_op_iterator_next (async_generator_object_p->frame_ctx.block_result, + async_generator_object_p->frame_ctx.stack_top_p[-1], + task_p->operation_value); if (ECMA_IS_VALUE_ERROR (result)) { @@ -256,6 +258,10 @@ ecma_async_generator_run (vm_executable_object_t *async_generator_object_p) /**< async_generator_object_p->frame_ctx.block_result = ECMA_VALUE_UNDEFINED; async_generator_object_p->frame_ctx.byte_code_p = opfunc_resume_executable_object_with_throw; + JERRY_ASSERT (async_generator_object_p->frame_ctx.stack_top_p[-1] == ECMA_VALUE_UNDEFINED + || ecma_is_value_object (async_generator_object_p->frame_ctx.stack_top_p[-1])); + async_generator_object_p->frame_ctx.stack_top_p--; + result = jcontext_take_exception (); } else diff --git a/jerry-core/ecma/operations/ecma-container-object.c b/jerry-core/ecma/operations/ecma-container-object.c index 17741635d..0015a6d2e 100644 --- a/jerry-core/ecma/operations/ecma-container-object.c +++ b/jerry-core/ecma/operations/ecma-container-object.c @@ -439,7 +439,7 @@ ecma_op_container_create (const ecma_value_t *arguments_list_p, /**< arguments l ecma_object_t *adder_func_p = ecma_get_object_from_value (result); - result = ecma_op_get_iterator (iterable, ECMA_VALUE_SYNC_ITERATOR); + result = ecma_op_get_iterator (iterable, ECMA_VALUE_SYNC_ITERATOR, NULL); if (ECMA_IS_VALUE_ERROR (result)) { diff --git a/jerry-core/ecma/operations/ecma-iterator-object.c b/jerry-core/ecma/operations/ecma-iterator-object.c index df6560088..054a11aa1 100644 --- a/jerry-core/ecma/operations/ecma-iterator-object.c +++ b/jerry-core/ecma/operations/ecma-iterator-object.c @@ -163,7 +163,7 @@ ecma_op_create_iterator_object (ecma_value_t iterated_value, /**< value from cre /** * GetIterator operation * - * See also: ECMA-262 v6, 7.4.1 + * See also: ECMA-262 v10, 7.4.1 * * Note: * Returned value must be freed with ecma_free_value. @@ -173,21 +173,28 @@ ecma_op_create_iterator_object (ecma_value_t iterated_value, /**< value from cre */ ecma_value_t ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */ - ecma_value_t method) /**< provided method argument */ + ecma_value_t method, /**< provided method argument */ + ecma_value_t *next_method_p) /**< [out] next method */ { + if (next_method_p != NULL) + { + /* TODO: NULL support should be removed after all functions support next method caching. */ + *next_method_p = ECMA_VALUE_UNDEFINED; + } + /* 1. */ if (ECMA_IS_VALUE_ERROR (value)) { return value; } - bool has_method = false; + bool use_default_method = false; /* 2. */ if (method == ECMA_VALUE_SYNC_ITERATOR) { /* 2.a */ - has_method = true; + use_default_method = true; method = ecma_op_get_method_by_symbol_id (value, LIT_GLOBAL_SYMBOL_ITERATOR); /* 2.b */ @@ -199,7 +206,7 @@ ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */ else if (method == ECMA_VALUE_ASYNC_ITERATOR) { /* TODO: CreateAsyncFromSyncIterator should be supported. */ - has_method = true; + use_default_method = true; method = ecma_op_get_method_by_symbol_id (value, LIT_GLOBAL_SYMBOL_ASYNC_ITERATOR); if (ECMA_IS_VALUE_ERROR (method)) @@ -212,13 +219,13 @@ ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */ if (!ecma_is_value_object (method) || !ecma_op_is_callable (method)) { ecma_free_value (method); - return ecma_raise_type_error (ECMA_ERR_MSG ("object is not iterable")); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator is not function")); } ecma_object_t *method_obj_p = ecma_get_object_from_value (method); ecma_value_t iterator = ecma_op_function_call (method_obj_p, value, NULL, 0); - if (has_method) + if (use_default_method) { ecma_deref_object (method_obj_p); } @@ -236,6 +243,27 @@ ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */ return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator is not an object.")); } + if (next_method_p != NULL) + { + ecma_object_t *obj_p = ecma_get_object_from_value (iterator); + ecma_value_t next_method = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_NEXT); + + if (ECMA_IS_VALUE_ERROR (next_method)) + { + ecma_free_value (iterator); + return next_method; + } + + if (ecma_is_value_object (next_method) && ecma_op_is_callable (next_method)) + { + *next_method_p = next_method; + } + else + { + ecma_free_value (next_method); + } + } + /* 6. */ return iterator; } /* ecma_op_get_iterator */ @@ -251,9 +279,9 @@ ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */ * @return iterator result object - if success * raised error - otherwise */ -ecma_value_t -ecma_op_iterator_next (ecma_value_t iterator, /**< iterator value */ - ecma_value_t value) /**< the routines's value argument */ +static ecma_value_t +ecma_op_iterator_next_old (ecma_value_t iterator, /**< iterator value */ + ecma_value_t value) /**< the routines's value argument */ { JERRY_ASSERT (ecma_is_value_object (iterator)); @@ -291,6 +319,42 @@ ecma_op_iterator_next (ecma_value_t iterator, /**< iterator value */ /* 5. */ return result; +} /* ecma_op_iterator_next_old */ + +/** + * IteratorNext operation + * + * See also: ECMA-262 v10, 7.4.2 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return iterator result object - if success + * raised error - otherwise + */ +ecma_value_t +ecma_op_iterator_next (ecma_value_t iterator, /**< iterator value */ + ecma_value_t next_method, /**< next method */ + ecma_value_t value) /**< the routines's value argument */ +{ + JERRY_ASSERT (ecma_is_value_object (iterator)); + + /* 1 - 2. */ + if (next_method == ECMA_VALUE_UNDEFINED) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator next() is not callable.")); + } + + ecma_object_t *next_method_obj_p = ecma_get_object_from_value (next_method); + + bool has_value = !ecma_is_value_empty (value); + + if (has_value) + { + return ecma_op_function_call (next_method_obj_p, iterator, &value, 1); + } + + return ecma_op_function_call (next_method_obj_p, iterator, NULL, 0); } /* ecma_op_iterator_next */ /** @@ -518,7 +582,7 @@ ecma_value_t ecma_op_iterator_step (ecma_value_t iterator) /**< iterator value */ { /* 1. */ - ecma_value_t result = ecma_op_iterator_next (iterator, ECMA_VALUE_EMPTY); + ecma_value_t result = ecma_op_iterator_next_old (iterator, ECMA_VALUE_EMPTY); /* 2. */ if (ECMA_IS_VALUE_ERROR (result)) @@ -569,6 +633,7 @@ ecma_op_iterator_step (ecma_value_t iterator) /**< iterator value */ ecma_value_t ecma_op_iterator_do (ecma_iterator_command_type_t command, /**< command to be executed */ ecma_value_t iterator, /**< iterator object */ + ecma_value_t next_method, /**< next method */ ecma_value_t value, /**< the routines's value argument */ bool *done_p) /**< it contains the logical value of the done property */ { @@ -576,16 +641,16 @@ ecma_op_iterator_do (ecma_iterator_command_type_t command, /**< command to be ex if (command == ECMA_ITERATOR_NEXT) { - result = ecma_op_iterator_next (iterator, value); + result = ecma_op_iterator_next (iterator, next_method, value); } - else if (command == ECMA_ITERATOR_RETURN) + else if (command == ECMA_ITERATOR_THROW) { - result = ecma_op_iterator_return (iterator, value); + result = ecma_op_iterator_throw (iterator, value); } else { - JERRY_ASSERT (command == ECMA_ITERATOR_THROW); - result = ecma_op_iterator_throw (iterator, value); + JERRY_ASSERT (command == ECMA_ITERATOR_RETURN); + result = ecma_op_iterator_return (iterator, value); } if (ECMA_IS_VALUE_ERROR (result)) diff --git a/jerry-core/ecma/operations/ecma-iterator-object.h b/jerry-core/ecma/operations/ecma-iterator-object.h index c5daf3df6..43db11ee3 100644 --- a/jerry-core/ecma/operations/ecma-iterator-object.h +++ b/jerry-core/ecma/operations/ecma-iterator-object.h @@ -33,8 +33,8 @@ typedef enum { ECMA_ITERATOR_NEXT, /**< generator should continue its execution */ - ECMA_ITERATOR_RETURN, /**< generator should perform a return operation */ ECMA_ITERATOR_THROW, /**< generator should perform a throw operation */ + ECMA_ITERATOR_RETURN, /**< generator should perform a return operation */ } ecma_iterator_command_type_t; /** @@ -54,13 +54,13 @@ ecma_value_t ecma_create_array_from_iter_element (ecma_value_t value, ecma_value_t index_value); ecma_value_t -ecma_op_get_iterator (ecma_value_t value, ecma_value_t method); +ecma_op_get_iterator (ecma_value_t value, ecma_value_t method, ecma_value_t *next_method_p); ecma_value_t ecma_op_iterator_value (ecma_value_t iter_result); ecma_value_t -ecma_op_iterator_next (ecma_value_t iterator, ecma_value_t value); +ecma_op_iterator_next (ecma_value_t iterator, ecma_value_t next_method, ecma_value_t value); ecma_value_t ecma_op_iterator_close (ecma_value_t iterator); @@ -70,7 +70,7 @@ ecma_op_iterator_step (ecma_value_t iterator); ecma_value_t ecma_op_iterator_do (ecma_iterator_command_type_t command, ecma_value_t iterator, - ecma_value_t value, bool *done_p); + ecma_value_t next_method, ecma_value_t value, bool *done_p); #endif /* ENABLED (JERRY_ESNEXT) */ diff --git a/jerry-core/ecma/operations/ecma-jobqueue.c b/jerry-core/ecma/operations/ecma-jobqueue.c index 7a13771ec..b17cedbf3 100644 --- a/jerry-core/ecma/operations/ecma-jobqueue.c +++ b/jerry-core/ecma/operations/ecma-jobqueue.c @@ -277,6 +277,10 @@ ecma_process_promise_async_reaction_job (ecma_job_promise_async_reaction_t *job_ JERRY_ASSERT (ecma_is_value_object (executable_object_p->frame_ctx.block_result)); executable_object_p->frame_ctx.block_result = ECMA_VALUE_UNDEFINED; executable_object_p->frame_ctx.byte_code_p = opfunc_resume_executable_object_with_throw; + + JERRY_ASSERT (executable_object_p->frame_ctx.stack_top_p[-1] == ECMA_VALUE_UNDEFINED + || ecma_is_value_object (executable_object_p->frame_ctx.stack_top_p[-1])); + executable_object_p->frame_ctx.stack_top_p--; } } @@ -303,6 +307,10 @@ ecma_process_promise_async_reaction_job (ecma_job_promise_async_reaction_t *job_ JERRY_ASSERT (ecma_is_value_object (executable_object_p->frame_ctx.block_result)); executable_object_p->frame_ctx.block_result = ECMA_VALUE_UNDEFINED; + + JERRY_ASSERT (executable_object_p->frame_ctx.stack_top_p[-1] == ECMA_VALUE_UNDEFINED + || ecma_is_value_object (executable_object_p->frame_ctx.stack_top_p[-1])); + executable_object_p->frame_ctx.stack_top_p--; } ecma_value_t result = opfunc_resume_executable_object (executable_object_p, job_p->argument); diff --git a/jerry-core/ecma/operations/ecma-typedarray-object.c b/jerry-core/ecma/operations/ecma-typedarray-object.c index 972f5be45..c1d61dd5e 100644 --- a/jerry-core/ecma/operations/ecma-typedarray-object.c +++ b/jerry-core/ecma/operations/ecma-typedarray-object.c @@ -777,7 +777,7 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje if (!ecma_is_value_undefined (using_iterator)) { /* 8.a */ - ecma_value_t iterator = ecma_op_get_iterator (items_val, using_iterator); + ecma_value_t iterator = ecma_op_get_iterator (items_val, using_iterator, NULL); ecma_free_value (using_iterator); /* 8.b */ diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 362bf76df..5617fff5a 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -339,7 +339,7 @@ opfunc_append_to_spread_array (ecma_value_t *stack_top_p, /**< current stack top ecma_value_t ret_value = ECMA_VALUE_ERROR; ecma_value_t spread_value = stack_top_p[i]; - ecma_value_t iterator = ecma_op_get_iterator (spread_value, ECMA_VALUE_SYNC_ITERATOR); + ecma_value_t iterator = ecma_op_get_iterator (spread_value, ECMA_VALUE_SYNC_ITERATOR, NULL); if (!ECMA_IS_VALUE_ERROR (iterator)) { @@ -432,7 +432,7 @@ opfunc_spread_arguments (ecma_value_t *stack_top_p, /**< pointer to the current ecma_value_t spread_value = *stack_top_p++; i++; - ecma_value_t iterator = ecma_op_get_iterator (spread_value, ECMA_VALUE_SYNC_ITERATOR); + ecma_value_t iterator = ecma_op_get_iterator (spread_value, ECMA_VALUE_SYNC_ITERATOR, NULL); if (!ECMA_IS_VALUE_ERROR (iterator)) { diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 7d5b3286f..ff504816a 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -2041,7 +2041,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_GET_ITERATOR: { - result = ecma_op_get_iterator (stack_top_p[-1], ECMA_VALUE_SYNC_ITERATOR); + result = ecma_op_get_iterator (stack_top_p[-1], ECMA_VALUE_SYNC_ITERATOR, NULL); if (ECMA_IS_VALUE_ERROR (result)) { @@ -2213,8 +2213,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (!(async_generator_object_p->u.class_prop.extra_info & ECMA_GENERATOR_ITERATE_AND_YIELD)); /* Byte code is executed at the first time. */ - left_value = *(--stack_top_p); - result = ecma_op_get_iterator (left_value, ECMA_VALUE_ASYNC_ITERATOR); + left_value = stack_top_p[-1]; + result = ecma_op_get_iterator (left_value, ECMA_VALUE_ASYNC_ITERATOR, stack_top_p - 1); if (ECMA_IS_VALUE_ERROR (result)) { @@ -2223,7 +2223,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_free_value (left_value); left_value = result; - result = ecma_op_iterator_next (left_value, ECMA_VALUE_UNDEFINED); + result = ecma_op_iterator_next (left_value, stack_top_p[-1], ECMA_VALUE_UNDEFINED); if (ECMA_IS_VALUE_ERROR (result)) { @@ -3786,7 +3786,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); - ecma_value_t iterator = ecma_op_get_iterator (value, ECMA_VALUE_SYNC_ITERATOR); + ecma_value_t iterator = ecma_op_get_iterator (value, ECMA_VALUE_SYNC_ITERATOR, NULL); ecma_free_value (value); diff --git a/tests/jerry/es.next/function-async-gen4.js b/tests/jerry/es.next/function-async-gen4.js new file mode 100644 index 000000000..0b8b33d20 --- /dev/null +++ b/tests/jerry/es.next/function-async-gen4.js @@ -0,0 +1,130 @@ +// 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 successCount = 0 + +function check_fulfilled(p, value, done) +{ + assert(p instanceof Promise) + + p.then(function(v) { + assert(v.value === value) + assert(v.done === done) + successCount++ + }, function() { + assert(false) + }) +} + +function check_rejected(p, value) +{ + assert(p instanceof Promise) + + p.then(function(v) { + assert(false) + }, function(v) { + assert(v === value) + successCount++ + }) +} + +// Test 1 + +var o1 = {} +var state1 = 0 +var async1 = { + [Symbol.asyncIterator]() { + return { + get next() { + assert(++state1 === 2) + return function () { + return { value:"Res", done:false } + } + }, + get throw() { + ++state1 + assert(state1 === 5 || state1 === 7 || state1 == 9) + return function (v) { + assert(v === "Input") + return { value:o1, done:false } + } + }, + get return() { + ++state1 + assert(state1 === 6 || state1 === 8 || state1 == 10) + return function (v) { + assert(v === o1) + return { value:4.5, done:false } + } + } + } + } +} + +async function *f1() { + assert(++state1 === 1) + yield *async1 + assert(false) +} + +var gen = f1() +check_fulfilled(gen.next(), "Res", false) +assert(++state1 === 3) +check_fulfilled(gen.throw("Input"), o1, false) +check_fulfilled(gen.return(o1), 4.5, false) + +check_fulfilled(gen.next(), "Res", false) +check_fulfilled(gen.throw("Input"), o1, false) +check_fulfilled(gen.return(o1), 4.5, false) + +check_fulfilled(gen.next(), "Res", false) +check_fulfilled(gen.throw("Input"), o1, false) +check_fulfilled(gen.return(o1), 4.5, false) +assert(++state1 === 4) + +// Test 2 + +var state2 = 0 +var async2 = { + [Symbol.asyncIterator]() { + return { + get next() { + assert(++state2 === 2) + return "Not callable" + } + } + } +} + +async function *f2() { + assert(++state2 === 1) + try { + yield *async2 + assert(false) + } catch (e) { + assert(e instanceof TypeError) + } + return "End" +} + +gen = f2() +check_fulfilled(gen.next(), "End", true) + +// END + +function __checkAsync() { + assert(state1 == 10) + assert(state2 == 2) + assert(successCount == 10) +} diff --git a/tests/jerry/es.next/generator-yield-iterator.js b/tests/jerry/es.next/generator-yield-iterator.js index 3b36d98d4..efab02bea 100644 --- a/tests/jerry/es.next/generator-yield-iterator.js +++ b/tests/jerry/es.next/generator-yield-iterator.js @@ -119,3 +119,88 @@ function *gen5() { g = gen5() check_result(g.next(), 1, false) check_result(g.throw(10), 3, false) + +var o = {} +var state = 0 +var iter6 = { + [Symbol.iterator]() { + return { + get next() { + assert(++state === 2) + return function () { + return { value:"Res", done:false } + } + }, + get throw() { + ++state + assert(state === 4 || state === 9 || state == 14) + return function (v) { + assert(v === "Input") + return { value:o, done:false } + } + }, + get return() { + ++state + assert(state === 6 || state === 11 || state == 16) + return function (v) { + assert(v === o) + return { value:4.5, done:false } + } + } + } + } +} + +function *gen6() { + assert(++state === 1) + yield *iter6 + assert(false) +} + +g = gen6() +check_result(g.next(), "Res", false) +assert(++state === 3) +check_result(g.throw("Input"), o, false) +assert(++state === 5) +check_result(g.return(o), 4.5, false) +assert(++state === 7) + +check_result(g.next(), "Res", false) +assert(++state === 8) +check_result(g.throw("Input"), o, false) +assert(++state === 10) +check_result(g.return(o), 4.5, false) +assert(++state === 12) + +check_result(g.next(), "Res", false) +assert(++state === 13) +check_result(g.throw("Input"), o, false) +assert(++state === 15) +check_result(g.return(o), 4.5, false) +assert(++state === 17) + +state = 0 +var iter7 = { + [Symbol.iterator]() { + return { + get next() { + assert(++state === 2) + return "Not callable" + } + } + } +} + +function *gen7() { + assert(++state === 1) + yield *iter7 + assert(false) +} + +g = gen7() +try { + g.next() + assert(false) +} catch (e) { + assert(e instanceof TypeError) +}