Implement async generators (#3916)
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
+21
-4
@@ -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
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user