mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Support caching of next method in generators. (#3937)
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
parent
f88489beef
commit
b7e3baeecb
@ -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 */
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
||||
@ -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 */
|
||||
|
||||
/**
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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))
|
||||
{
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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) */
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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))
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
130
tests/jerry/es.next/function-async-gen4.js
Normal file
130
tests/jerry/es.next/function-async-gen4.js
Normal file
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user