Implement for-await-of statement. (#3946)

AsyncIteratorClose has not supported yet.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2020-06-30 11:21:50 +02:00
committed by GitHub
parent 0b404ea893
commit 5535ea88ac
20 changed files with 729 additions and 199 deletions
+54 -3
View File
@@ -730,6 +730,12 @@ opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, /*
ecma_value_t *stack_top_p = executable_object_p->frame_ctx.stack_top_p;
if (value != ECMA_VALUE_EMPTY)
{
*stack_top_p = value;
executable_object_p->frame_ctx.stack_top_p = stack_top_p + 1;
}
if (executable_object_p->frame_ctx.context_depth > 0)
{
while (register_p < register_end_p)
@@ -752,9 +758,6 @@ opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, /*
ecma_ref_if_object (executable_object_p->frame_ctx.block_result);
*register_p++ = value;
executable_object_p->frame_ctx.stack_top_p = register_p;
JERRY_ASSERT (ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED (executable_object_p->extended_object.u.class_prop.extra_info));
executable_object_p->extended_object.u.class_prop.extra_info |= ECMA_EXECUTABLE_OBJECT_RUNNING;
@@ -840,6 +843,54 @@ opfunc_async_generator_yield (ecma_extended_object_t *async_generator_object_p,
}
} /* opfunc_async_generator_yield */
/**
* Creates a new executable object and awaits for the value
*
* Note:
* extra_flags can be used to set additional extra_info flags
*
* @return a new Promise object on success, error otherwise
*/
ecma_value_t
opfunc_async_create_and_await (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
ecma_value_t value, /**< awaited value (takes reference) */
uint16_t extra_flags) /**< extra flags */
{
JERRY_ASSERT (frame_ctx_p->block_result == ECMA_VALUE_UNDEFINED);
/* TODO: An CBC_FUNCTION_ASYNC_ARROW should be defined. */
JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (frame_ctx_p->bytecode_header_p->status_flags) == CBC_FUNCTION_ASYNC
|| CBC_FUNCTION_GET_TYPE (frame_ctx_p->bytecode_header_p->status_flags) == CBC_FUNCTION_ARROW);
ecma_object_t *promise_p = ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE);
ecma_value_t result = ecma_promise_reject_or_resolve (ecma_make_object_value (promise_p), value, true);
ecma_free_value (value);
if (ECMA_IS_VALUE_ERROR (result))
{
return result;
}
vm_executable_object_t *executable_object_p;
executable_object_p = opfunc_create_executable_object (frame_ctx_p, VM_CREATE_EXECUTABLE_OBJECT_ASYNC);
executable_object_p->extended_object.u.class_prop.extra_info |= extra_flags;
ecma_promise_async_then (result, ecma_make_object_value ((ecma_object_t *) executable_object_p));
ecma_deref_object ((ecma_object_t *) executable_object_p);
ecma_free_value (result);
ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target);
JERRY_CONTEXT (current_new_target) = promise_p;
result = ecma_op_create_promise_object (ECMA_VALUE_EMPTY, ECMA_PROMISE_EXECUTOR_EMPTY);
JERRY_ASSERT (ecma_is_value_object (result));
executable_object_p->frame_ctx.block_result = result;
JERRY_CONTEXT (current_new_target) = old_new_target_p;
return result;
} /* opfunc_async_create_and_await */
/**
* Implicit class constructor handler when the classHeritage is not present.
*
+3
View File
@@ -138,6 +138,9 @@ opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, ec
void
opfunc_async_generator_yield (ecma_extended_object_t *async_generator_object_p, ecma_value_t value);
ecma_value_t
opfunc_async_create_and_await (vm_frame_ctx_t *frame_ctx_p, ecma_value_t value, uint16_t extra_flags);
ecma_value_t
opfunc_create_implicit_class_constructor (uint8_t opcode);
+17 -10
View File
@@ -28,10 +28,13 @@
*/
JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_BLOCK_CONTEXT_STACK_ALLOCATION,
parser_with_context_stack_allocation_must_be_equal_to_parser_block_context_stack_allocation);
with_context_stack_allocation_must_be_equal_to_block_context_stack_allocation);
JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_TRY_CONTEXT_STACK_ALLOCATION,
parser_with_context_stack_allocation_must_be_equal_to_parser_block_context_stack_allocation);
with_context_stack_allocation_must_be_equal_to_block_context_stack_allocation);
JERRY_STATIC_ASSERT (PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION == PARSER_FOR_AWAIT_OF_CONTEXT_STACK_ALLOCATION,
for_of_context_stack_allocation_must_be_equal_to_for_await_of_context_stack_allocation);
/**
* Abort (finalize) the current stack context, and remove it.
@@ -79,6 +82,7 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
}
#if ENABLED (JERRY_ESNEXT)
case VM_CONTEXT_FOR_OF:
case VM_CONTEXT_FOR_AWAIT_OF:
{
ecma_value_t iterator = vm_stack_top_p[-3];
ecma_free_value (vm_stack_top_p[-2]);
@@ -313,7 +317,7 @@ vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
#if ENABLED (JERRY_ESNEXT)
/**
* Get the offsets of ecma values from the specified item of a context.
* Get the offsets of ecma values corresponding to the passed context.
*
* @return array of offsets, last item represents the size of the context item
*/
@@ -325,7 +329,7 @@ vm_get_context_value_offsets (ecma_value_t *context_item_p) /**< any item of a c
case VM_CONTEXT_FINALLY_THROW:
case VM_CONTEXT_FINALLY_RETURN:
{
return (2 << (VM_CONTEXT_OFFSET_SHIFT)) | PARSER_FINALLY_CONTEXT_STACK_ALLOCATION;
return (PARSER_FINALLY_CONTEXT_STACK_ALLOCATION << VM_CONTEXT_OFFSET_SHIFT) | 2;
}
case VM_CONTEXT_FINALLY_JUMP:
{
@@ -338,16 +342,19 @@ vm_get_context_value_offsets (ecma_value_t *context_item_p) /**< any item of a c
{
return PARSER_WITH_CONTEXT_STACK_ALLOCATION;
}
case VM_CONTEXT_FOR_OF:
case VM_CONTEXT_FOR_IN:
{
return ((4 << (VM_CONTEXT_OFFSET_SHIFT * 3))
| (3 << (VM_CONTEXT_OFFSET_SHIFT * 2))
| (2 << (VM_CONTEXT_OFFSET_SHIFT))
| PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
return (PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION << VM_CONTEXT_OFFSET_SHIFT) | 4;
}
default:
{
return (4 << (VM_CONTEXT_OFFSET_SHIFT)) | PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION;
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (context_item_p[-1]) == VM_CONTEXT_FOR_OF
|| VM_GET_CONTEXT_TYPE (context_item_p[-1]) == VM_CONTEXT_FOR_AWAIT_OF);
return ((PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION << (VM_CONTEXT_OFFSET_SHIFT * 3))
| (4 << (VM_CONTEXT_OFFSET_SHIFT * 2))
| (3 << VM_CONTEXT_OFFSET_SHIFT)
| 2);
}
}
} /* vm_get_context_value_offsets */
+2 -1
View File
@@ -74,6 +74,7 @@ typedef enum
VM_CONTEXT_FOR_IN, /**< for-in context */
#if ENABLED (JERRY_ESNEXT)
VM_CONTEXT_FOR_OF, /**< for-of context */
VM_CONTEXT_FOR_AWAIT_OF, /**< for-await-of context */
#endif /* ENABLED (JERRY_ESNEXT) */
} vm_stack_context_type_t;
@@ -94,7 +95,7 @@ typedef enum
#define VM_CONTEXT_HAS_NEXT_OFFSET(offsets) ((offsets) >= (1 << VM_CONTEXT_OFFSET_SHIFT))
/**
* Gets the next offset from the offset array.
* Get the next offset from the offset array.
*/
#define VM_CONTEXT_GET_NEXT_OFFSET(offsets) (-((int32_t) ((offsets) & ((1 << VM_CONTEXT_OFFSET_SHIFT) - 1))))
+121 -47
View File
@@ -2210,7 +2210,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
ecma_extended_object_t *async_generator_object_p = VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
JERRY_ASSERT (!(async_generator_object_p->u.class_prop.extra_info & ECMA_GENERATOR_ITERATE_AND_YIELD));
JERRY_ASSERT (!(async_generator_object_p->u.class_prop.extra_info
& ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD));
/* Byte code is executed at the first time. */
left_value = stack_top_p[-1];
@@ -2237,7 +2238,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
goto error;
}
async_generator_object_p->u.class_prop.extra_info |= ECMA_GENERATOR_ITERATE_AND_YIELD;
async_generator_object_p->u.class_prop.extra_info |= ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD;
frame_ctx_p->block_result = left_value;
frame_ctx_p->call_operation = VM_EXEC_RETURN;
@@ -2247,50 +2248,21 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
}
case VM_OC_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))
if (JERRY_UNLIKELY (frame_ctx_p->block_result == ECMA_VALUE_UNDEFINED))
{
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;
result = opfunc_async_create_and_await (frame_ctx_p, *stack_top_p, 0);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
return result;
}
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;
if (frame_ctx_p->block_result == ECMA_VALUE_UNDEFINED)
{
vm_executable_object_t *executable_object_p;
executable_object_p = opfunc_create_executable_object (frame_ctx_p, VM_CREATE_EXECUTABLE_OBJECT_ASYNC);
ecma_promise_async_then (result, ecma_make_object_value ((ecma_object_t *) executable_object_p));
ecma_deref_object ((ecma_object_t *) executable_object_p);
ecma_free_value (result);
ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target);
JERRY_CONTEXT (current_new_target) = ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE);
result = ecma_op_create_promise_object (ECMA_VALUE_EMPTY, ECMA_PROMISE_EXECUTOR_EMPTY);
JERRY_ASSERT (ecma_is_value_object (result));
executable_object_p->frame_ctx.block_result = result;
JERRY_CONTEXT (current_new_target) = old_new_target_p;
}
else
{
ecma_object_t *object_p = (ecma_object_t *) VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
ecma_promise_async_then (result, ecma_make_object_value (object_p));
ecma_free_value (result);
result = ECMA_VALUE_UNDEFINED;
}
return result;
/* FALLTHRU */
}
case VM_OC_GENERATOR_AWAIT:
{
@@ -3668,7 +3640,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
frame_ctx_p->lex_env_p = with_env_p;
continue;
}
case VM_OC_FOR_IN_CREATE_CONTEXT:
case VM_OC_FOR_IN_INIT:
{
ecma_value_t value = *(--stack_top_p);
@@ -3780,7 +3752,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
continue;
}
#if ENABLED (JERRY_ESNEXT)
case VM_OC_FOR_OF_CREATE_CONTEXT:
case VM_OC_FOR_OF_INIT:
{
ecma_value_t value = *(--stack_top_p);
@@ -3844,7 +3816,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
case VM_OC_FOR_OF_GET_NEXT:
{
ecma_value_t *context_top_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth;
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (context_top_p[-1]) == VM_CONTEXT_FOR_OF);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (context_top_p[-1]) == VM_CONTEXT_FOR_OF
|| VM_GET_CONTEXT_TYPE (context_top_p[-1]) == VM_CONTEXT_FOR_AWAIT_OF);
*stack_top_p++ = context_top_p[-2];
context_top_p[-2] = ECMA_VALUE_UNDEFINED;
@@ -3853,6 +3826,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
case VM_OC_FOR_OF_HAS_NEXT:
{
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FOR_OF);
result = ecma_op_iterator_step (stack_top_p[-3], stack_top_p[-4]);
@@ -3885,6 +3859,106 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
byte_code_p = byte_code_start_p + branch_offset;
continue;
}
case VM_OC_FOR_AWAIT_OF_INIT:
{
ecma_value_t value = *(--stack_top_p);
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
ecma_value_t next_method;
result = ecma_op_get_iterator (value, ECMA_VALUE_ASYNC_ITERATOR, &next_method);
ecma_free_value (value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_value_t iterator = result;
result = ecma_op_iterator_next (result, next_method, ECMA_VALUE_EMPTY);
if (ECMA_IS_VALUE_ERROR (result))
{
ecma_free_value (iterator);
ecma_free_value (next_method);
goto error;
}
branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p);
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_AWAIT_OF_CONTEXT_STACK_ALLOCATION);
stack_top_p += PARSER_FOR_AWAIT_OF_CONTEXT_STACK_ALLOCATION;
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_FOR_AWAIT_OF, branch_offset);
stack_top_p[-2] = ECMA_VALUE_UNDEFINED;
stack_top_p[-3] = iterator;
stack_top_p[-4] = next_method;
if (byte_code_p[0] == CBC_EXT_OPCODE && byte_code_p[1] == CBC_EXT_CLONE_CONTEXT)
{
/* No need to duplicate the first context. */
byte_code_p += 2;
}
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;
uint16_t extra_flags = (ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD
| (ECMA_AWAIT_FOR_NEXT << ECMA_AWAIT_STATE_SHIFT));
if (CBC_FUNCTION_GET_TYPE (frame_ctx_p->bytecode_header_p->status_flags) == CBC_FUNCTION_ASYNC_GENERATOR
|| frame_ctx_p->block_result != ECMA_VALUE_UNDEFINED)
{
ecma_extended_object_t *executable_object_p = VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
result = ecma_promise_async_await (executable_object_p, result);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
executable_object_p->u.class_prop.extra_info |= extra_flags;
return ECMA_VALUE_UNDEFINED;
}
result = opfunc_async_create_and_await (frame_ctx_p, result, extra_flags);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
return result;
}
case VM_OC_FOR_AWAIT_OF_HAS_NEXT:
{
JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p);
JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_FOR_AWAIT_OF);
result = ecma_op_iterator_next (stack_top_p[-3], stack_top_p[-4], ECMA_VALUE_EMPTY);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_extended_object_t *executable_object_p = VM_GET_EXECUTABLE_OBJECT (frame_ctx_p);
result = ecma_promise_async_await (executable_object_p, result);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
uint16_t extra_flags = (ECMA_EXECUTABLE_OBJECT_DO_AWAIT_OR_YIELD
| (ECMA_AWAIT_FOR_NEXT << ECMA_AWAIT_STATE_SHIFT));
executable_object_p->u.class_prop.extra_info |= extra_flags;
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_start_p + branch_offset;
frame_ctx_p->stack_top_p = stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
#endif /* ENABLED (JERRY_ESNEXT) */
case VM_OC_TRY:
{
+11 -7
View File
@@ -206,7 +206,7 @@ typedef enum
VM_OC_BLOCK_CREATE_CONTEXT, /**< create lexical environment for blocks enclosed in braces */
VM_OC_WITH, /**< with */
VM_OC_FOR_IN_CREATE_CONTEXT, /**< for in create context */
VM_OC_FOR_IN_INIT, /**< for-in init context */
VM_OC_FOR_IN_GET_NEXT, /**< get next */
VM_OC_FOR_IN_HAS_NEXT, /**< has next */
@@ -243,9 +243,11 @@ typedef enum
VM_OC_CLONE_CONTEXT, /**< clone lexical environment with let/const declarations */
VM_OC_SET_COMPUTED_PROPERTY, /**< set computed property */
VM_OC_FOR_OF_CREATE_CONTEXT, /**< for of create context */
VM_OC_FOR_OF_GET_NEXT, /**< get next */
VM_OC_FOR_OF_HAS_NEXT, /**< has next */
VM_OC_FOR_OF_INIT, /**< for-of init context */
VM_OC_FOR_OF_GET_NEXT, /**< for-of get next */
VM_OC_FOR_OF_HAS_NEXT, /**< for-of has next */
VM_OC_FOR_AWAIT_OF_INIT, /**< for-await-of init context */
VM_OC_FOR_AWAIT_OF_HAS_NEXT, /**< for-await-of has next */
VM_OC_LOCAL_EVAL, /**< eval in local context */
VM_OC_SUPER_CALL, /**< call the 'super' constructor */
@@ -312,9 +314,11 @@ typedef enum
VM_OC_CLONE_CONTEXT = VM_OC_NONE, /**< clone lexical environment with let/const declarations */
VM_OC_SET_COMPUTED_PROPERTY = VM_OC_NONE, /**< set computed property is unused */
VM_OC_FOR_OF_CREATE_CONTEXT = VM_OC_NONE, /**< for of create context */
VM_OC_FOR_OF_GET_NEXT = VM_OC_NONE, /**< get next */
VM_OC_FOR_OF_HAS_NEXT = VM_OC_NONE, /**< has next */
VM_OC_FOR_OF_INIT = VM_OC_NONE, /**< for-of init context */
VM_OC_FOR_OF_GET_NEXT = VM_OC_NONE, /**< for-of get next */
VM_OC_FOR_OF_HAS_NEXT = VM_OC_NONE, /**< for-of has next */
VM_OC_FOR_AWAIT_OF_INIT = VM_OC_NONE, /**< for-await-of init context */
VM_OC_FOR_AWAIT_OF_HAS_NEXT = VM_OC_NONE, /**< for-await-of has next */
VM_OC_LOCAL_EVAL = VM_OC_NONE, /**< eval in local context */
VM_OC_SUPER_CALL = VM_OC_NONE, /**< call the 'super' constructor */