Implement async generators (#3916)

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2020-06-22 13:54:18 +02:00
committed by GitHub
parent 0f0041d720
commit b2a6109430
32 changed files with 1247 additions and 50 deletions
+21 -4
View File
@@ -600,11 +600,20 @@ opfunc_create_executable_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context
size_t total_size = JERRY_ALIGNUP (sizeof (vm_executable_object_t) + size, sizeof (uintptr_t));
ecma_object_t *proto_p = NULL;
/* Async function objects are not accessible, so their class_id is not relevant. */
uint16_t class_id = LIT_MAGIC_STRING_GENERATOR_UL;
if (type == VM_CREATE_EXECUTABLE_OBJECT_GENERATOR)
{
proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_function_obj_p),
ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE);
ecma_builtin_id_t default_proto_id = ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE;
if (CBC_FUNCTION_GET_TYPE (frame_ctx_p->bytecode_header_p->status_flags) == CBC_FUNCTION_ASYNC_GENERATOR)
{
default_proto_id = ECMA_BUILTIN_ID_ASYNC_GENERATOR_PROTOTYPE;
class_id = LIT_MAGIC_STRING_ASYNC_GENERATOR_UL;
}
proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_function_obj_p), default_proto_id);
}
ecma_object_t *object_p = ecma_create_object (proto_p,
@@ -618,9 +627,9 @@ opfunc_create_executable_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context
ecma_deref_object (proto_p);
}
/* Async function objects are not accessible, so their class_id is not relevant. */
executable_object_p->extended_object.u.class_prop.class_id = LIT_MAGIC_STRING_GENERATOR_UL;
executable_object_p->extended_object.u.class_prop.class_id = class_id;
executable_object_p->extended_object.u.class_prop.extra_info = 0;
ECMA_SET_INTERNAL_VALUE_ANY_POINTER (executable_object_p->extended_object.u.class_prop.u.head, NULL);
JERRY_ASSERT (!frame_ctx_p->is_eval_code);
@@ -683,6 +692,14 @@ const uint8_t opfunc_resume_executable_object_with_throw[1] =
CBC_THROW
};
/**
* Byte code which resumes an executable object with return
*/
const uint8_t opfunc_resume_executable_object_with_return[2] =
{
CBC_EXT_OPCODE, CBC_EXT_RETURN
};
/**
* Resume the execution of an inactive executable object
*
+1
View File
@@ -130,6 +130,7 @@ vm_executable_object_t *
opfunc_create_executable_object (vm_frame_ctx_t *frame_ctx_p, vm_create_executable_object_type_t type);
extern const uint8_t opfunc_resume_executable_object_with_throw[];
extern const uint8_t opfunc_resume_executable_object_with_return[];
ecma_value_t
opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, ecma_value_t value);
+60
View File
@@ -482,6 +482,11 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
func_obj_p = ecma_op_create_generator_function_object (frame_ctx_p->lex_env_p, bytecode_p);
break;
}
case CBC_FUNCTION_ASYNC_GENERATOR:
{
func_obj_p = ecma_op_create_async_generator_function_object (frame_ctx_p->lex_env_p, bytecode_p);
break;
}
case CBC_FUNCTION_ARROW:
{
func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p,
@@ -2190,6 +2195,37 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
frame_ctx_p->stack_top_p = --stack_top_p;
return *stack_top_p;
}
case VM_OC_ASYNC_YIELD:
{
const uintptr_t object_offset = (uintptr_t) offsetof (vm_executable_object_t, frame_ctx);
ecma_extended_object_t *async_generator_object_p;
async_generator_object_p = (ecma_extended_object_t *) (((uintptr_t) frame_ctx_p) - object_offset);
ecma_async_generator_task_t *task_p;
task_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_async_generator_task_t,
async_generator_object_p->u.class_prop.u.head);
ecma_value_t iter_result = ecma_create_iter_result_object (stack_top_p[-1], ECMA_VALUE_FALSE);
ecma_fulfill_promise (task_p->promise, iter_result);
ecma_free_value (iter_result);
ecma_free_value (stack_top_p[-1]);
async_generator_object_p->u.class_prop.u.head = task_p->next;
if (!ECMA_IS_INTERNAL_VALUE_NULL (task_p->next))
{
ecma_value_t executable_object = ecma_make_object_value ((ecma_object_t *) async_generator_object_p);
ecma_enqueue_promise_async_generator_job (executable_object);
}
JERRY_ASSERT (task_p->operation_value == ECMA_VALUE_UNDEFINED);
jmem_heap_free_block (task_p, sizeof (ecma_async_generator_task_t));
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = --stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
case VM_OC_AWAIT:
{
ecma_value_t promise = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE));
@@ -2239,6 +2275,30 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
return result;
}
case VM_OC_GENERATOR_AWAIT:
{
ecma_value_t promise = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE));
ecma_value_t argument = *(--stack_top_p);
result = ecma_promise_reject_or_resolve (promise, argument, true);
ecma_free_value (argument);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = stack_top_p;
const uintptr_t object_offset = (uintptr_t) offsetof (vm_executable_object_t, frame_ctx);
ecma_object_t *object_p = (ecma_object_t *) (((uintptr_t) frame_ctx_p) - object_offset);
ecma_promise_async_then (result, ecma_make_object_value (object_p));
ecma_free_value (result);
return ECMA_VALUE_UNDEFINED;
}
case VM_OC_EXT_RETURN:
{
result = left_value;
+4
View File
@@ -271,7 +271,9 @@ typedef enum
VM_OC_SPREAD_ARGUMENTS, /**< perform function call/construct with spreaded arguments */
VM_OC_CREATE_GENERATOR, /**< create a generator object */
VM_OC_YIELD, /**< yield operation */
VM_OC_ASYNC_YIELD, /**< async yield operation */
VM_OC_AWAIT, /**< await operation */
VM_OC_GENERATOR_AWAIT, /**< generator await operation */
VM_OC_EXT_RETURN, /**< return which also clears the stack */
VM_OC_ASYNC_EXIT, /**< return from async function */
VM_OC_STRING_CONCAT, /**< string concatenation */
@@ -340,7 +342,9 @@ typedef enum
VM_OC_SPREAD_ARGUMENTS = VM_OC_NONE, /**< perform function call/construct with spreaded arguments */
VM_OC_CREATE_GENERATOR = VM_OC_NONE, /**< create a generator object */
VM_OC_YIELD = VM_OC_NONE, /**< yield operation */
VM_OC_ASYNC_YIELD = VM_OC_NONE, /**< async yield operation */
VM_OC_AWAIT = VM_OC_NONE, /**< await operation */
VM_OC_GENERATOR_AWAIT = VM_OC_NONE, /**< generator await operation */
VM_OC_EXT_RETURN = VM_OC_NONE, /**< return which also clears the stack */
VM_OC_ASYNC_EXIT = VM_OC_NONE, /**< return from async function */
VM_OC_STRING_CONCAT = VM_OC_NONE, /**< string concatenation */