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
+40
View File
@@ -404,6 +404,27 @@ ecma_gc_mark_executable_object (ecma_object_t *object_p) /**< object */
{
vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p;
if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_ASYNC_GENERATOR_CALLED)
{
ecma_value_t task = executable_object_p->extended_object.u.class_prop.u.head;
while (!ECMA_IS_INTERNAL_VALUE_NULL (task))
{
ecma_async_generator_task_t *task_p;
task_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_async_generator_task_t, task);
JERRY_ASSERT (ecma_is_value_object (task_p->promise));
ecma_gc_set_object_visited (ecma_get_object_from_value (task_p->promise));
if (ecma_is_value_object (task_p->operation_value))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (task_p->operation_value));
}
task = task_p->next;
}
}
if (!ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED (executable_object_p->extended_object.u.class_prop.extra_info))
{
/* All objects referenced by running executable objects are strong roots,
@@ -584,6 +605,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
#endif /* ENABLED (JERRY_BUILTIN_CONTAINER) */
#if ENABLED (JERRY_ESNEXT)
case LIT_MAGIC_STRING_GENERATOR_UL:
case LIT_MAGIC_STRING_ASYNC_GENERATOR_UL:
{
ecma_gc_mark_executable_object (object_p);
break;
@@ -850,6 +872,23 @@ ecma_gc_free_executable_object (ecma_object_t *object_p) /**< object */
ecma_bytecode_deref ((ecma_compiled_code_t *) bytecode_header_p);
if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_ASYNC_GENERATOR_CALLED)
{
ecma_value_t task = executable_object_p->extended_object.u.class_prop.u.head;
while (!ECMA_IS_INTERNAL_VALUE_NULL (task))
{
ecma_async_generator_task_t *task_p;
task_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_async_generator_task_t, task);
JERRY_ASSERT (ecma_is_value_object (task_p->promise));
ecma_free_value_if_not_object (task_p->operation_value);
task = task_p->next;
jmem_heap_free_block (task_p, sizeof (ecma_async_generator_task_t));
}
}
if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED)
{
return size;
@@ -1167,6 +1206,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
#endif /* ENABLED (JERRY_BUILTIN_DATAVIEW) */
#if ENABLED (JERRY_ESNEXT)
case LIT_MAGIC_STRING_GENERATOR_UL:
case LIT_MAGIC_STRING_ASYNC_GENERATOR_UL:
{
ext_object_size = ecma_gc_free_executable_object (object_p);
break;
+20
View File
@@ -120,6 +120,7 @@ typedef enum
ECMA_PARSE_FUNCTION_CONTEXT = (1u << 8), /**< function context is present (ECMA_PARSE_DIRECT_EVAL must be set) */
ECMA_PARSE_GENERATOR_FUNCTION = (1u << 9), /**< generator function is parsed */
ECMA_PARSE_ASYNC_FUNCTION = (1u << 10), /**< async function is parsed */
/* These flags are internally used by the parser. */
#ifndef JERRY_NDEBUG
@@ -870,6 +871,7 @@ typedef struct
ecma_value_t value; /**< value of the object (e.g. boolean, number, string, etc.) */
uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */
ecma_value_t target; /**< [[ProxyTarget]] internal property */
ecma_value_t head; /**< points to the async generator task queue head item */
} u;
} class_prop;
@@ -1862,6 +1864,7 @@ typedef enum
ECMA_EXECUTABLE_OBJECT_RUNNING = (1u << 1), /**< executable object is currently running */
/* Generator specific flags. */
ECMA_GENERATOR_ITERATE_AND_YIELD = (1u << 2), /**< the generator performs a yield* operation */
ECMA_ASYNC_GENERATOR_CALLED = (1u << 3), /**< the async generator was executed before */
} ecma_executable_object_flags_t;
/**
@@ -1870,6 +1873,23 @@ typedef enum
#define ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED(extra_info) \
(!((extra_info) & (ECMA_EXECUTABLE_OBJECT_COMPLETED | ECMA_EXECUTABLE_OBJECT_RUNNING)))
/**
* Enqueued task of an AsyncGenerator.
*
* An execution of a task has three steps:
* 1) Perform a next/throw/return operation
* 2) Resume the execution of the AsyncGenerator
* 3) Fulfill or reject a promise if the AsyncGenerator yielded a value
* (these Promises are created by the AsyncGenerator itself)
*/
typedef struct
{
ecma_value_t next; /**< points to the next task which will be performed after this task is completed */
ecma_value_t promise; /**< promise which will be fulfilled or rejected after this task is completed */
ecma_value_t operation_value; /**< value argument of the operation */
uint8_t operation_type; /**< type of operation (see ecma_async_generator_operation_type_t) */
} ecma_async_generator_task_t;
#endif /* ENABLED (JERRY_ESNEXT) */
#if ENABLED (JERRY_BUILTIN_DATAVIEW)
+14 -2
View File
@@ -127,13 +127,13 @@ typedef enum
* Set an internal property value from pointer.
*/
#define ECMA_SET_INTERNAL_VALUE_POINTER(field, pointer) \
(field) = ((ecma_value_t) pointer)
((field) = ((ecma_value_t) pointer))
/**
* Set an internal property value from pointer. Pointer can be NULL.
*/
#define ECMA_SET_INTERNAL_VALUE_ANY_POINTER(field, pointer) \
(field) = ((ecma_value_t) pointer)
((field) = ((ecma_value_t) pointer))
/**
* Convert an internal property value to pointer.
@@ -147,6 +147,12 @@ typedef enum
#define ECMA_GET_INTERNAL_VALUE_ANY_POINTER(type, field) \
((type *) field)
/**
* Checks whether an internal property is NULL.
*/
#define ECMA_IS_INTERNAL_VALUE_NULL(field) \
((field) == ((ecma_value_t) NULL))
#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
/**
@@ -173,6 +179,12 @@ typedef enum
#define ECMA_GET_INTERNAL_VALUE_ANY_POINTER(type, field) \
ECMA_GET_POINTER (type, field)
/**
* Checks whether an internal property is NULL.
*/
#define ECMA_IS_INTERNAL_VALUE_NULL(field) \
((field) == ((ecma_value_t) JMEM_CP_NULL))
#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */
/**