Improve destructuring patterns (#4527)

- Fix evaluation order of the operands
- Implement proper iterator closing of array destructuring
- Support next method caching

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
This commit is contained in:
Robert Fancsik
2021-02-04 13:11:11 +01:00
committed by GitHub
parent 3bb67397a0
commit e7d11eaf9e
12 changed files with 389 additions and 354 deletions
+115 -38
View File
@@ -1001,6 +1001,12 @@ opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
opcode_data &= (uint32_t) ~VM_OC_PUT_BLOCK; \
}
/**
* Get the end of the existing topmost context
*/
#define VM_LAST_CONTEXT_END() \
(VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth)
/**
* Run generic byte code.
*
@@ -2307,24 +2313,39 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
*stack_top_p++ = result;
continue;
}
case VM_OC_GET_ITERATOR:
case VM_OC_ITERATOR_CONTEXT_CREATE:
{
result = ecma_op_get_iterator (stack_top_p[-1], ECMA_VALUE_SYNC_ITERATOR, NULL);
result = ecma_op_get_iterator (stack_top_p[-1], ECMA_VALUE_SYNC_ITERATOR, &left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
*stack_top_p++ = result;
uint32_t context_size = (uint32_t) (stack_top_p
+ PARSER_ITERATOR_CONTEXT_STACK_ALLOCATION
- VM_LAST_CONTEXT_END ());
stack_top_p += PARSER_ITERATOR_CONTEXT_STACK_ALLOCATION;
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, context_size);
stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_ITERATOR, context_size) | VM_CONTEXT_CLOSE_ITERATOR;
stack_top_p[-2] = result;
stack_top_p[-3] = left_value;
continue;
}
case VM_OC_ITERATOR_STEP:
{
result = ecma_op_iterator_step (stack_top_p[-1], ECMA_VALUE_EMPTY);
ecma_value_t *last_context_end_p = VM_LAST_CONTEXT_END ();
ecma_value_t iterator = last_context_end_p[-2];
ecma_value_t next_method = last_context_end_p[-3];
result = ecma_op_iterator_step (iterator, next_method);
if (ECMA_IS_VALUE_ERROR (result))
{
last_context_end_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
goto error;
}
@@ -2337,24 +2358,38 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
if (ECMA_IS_VALUE_ERROR (value))
{
last_context_end_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
result = value;
goto error;
}
}
else
{
last_context_end_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
}
*stack_top_p++ = value;
continue;
}
case VM_OC_ITERATOR_CLOSE:
case VM_OC_ITERATOR_CONTEXT_END:
{
result = ecma_op_iterator_close (left_value);
JERRY_ASSERT (VM_LAST_CONTEXT_END () == stack_top_p);
if (ECMA_IS_VALUE_ERROR (result))
if (stack_top_p[-1] & VM_CONTEXT_CLOSE_ITERATOR)
{
goto error;
stack_top_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
result = ecma_op_iterator_close (stack_top_p[-2]);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
}
goto free_left_value;
stack_top_p = vm_stack_context_abort_variable_length (frame_ctx_p,
stack_top_p,
PARSER_ITERATOR_CONTEXT_STACK_ALLOCATION);
continue;
}
case VM_OC_DEFAULT_INITIALIZER:
{
@@ -2373,21 +2408,26 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
ecma_object_t *array_p = ecma_op_new_array_object (0);
JERRY_ASSERT (ecma_op_object_is_fast_array (array_p));
ecma_value_t iterator = stack_top_p[-1];
ecma_value_t *last_context_end_p = VM_LAST_CONTEXT_END ();
ecma_value_t iterator = last_context_end_p[-2];
ecma_value_t next_method = last_context_end_p[-3];
uint32_t index = 0;
while (true)
{
result = ecma_op_iterator_step (iterator, ECMA_VALUE_EMPTY);
result = ecma_op_iterator_step (iterator, next_method);
if (ECMA_IS_VALUE_ERROR (result))
{
last_context_end_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
ecma_deref_object (array_p);
goto error;
}
if (ecma_is_value_false (result))
{
last_context_end_p[-1] &= (uint32_t) ~VM_CONTEXT_CLOSE_ITERATOR;
break;
}
@@ -2409,16 +2449,51 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
*stack_top_p++ = ecma_make_object_value (array_p);
continue;
}
case VM_OC_INITIALIZER_PUSH_LIST:
case VM_OC_OBJ_INIT_CONTEXT_CREATE:
{
stack_top_p++;
stack_top_p[-1] = stack_top_p[-2];
stack_top_p[-2] = ecma_make_object_value (ecma_op_new_array_object (0));
left_value = stack_top_p[-1];
vm_stack_context_type_t context_type = VM_CONTEXT_OBJ_INIT;
uint32_t context_stack_allocation = PARSER_OBJ_INIT_CONTEXT_STACK_ALLOCATION;
if (opcode == CBC_EXT_OBJ_INIT_REST_CONTEXT_CREATE)
{
context_type = VM_CONTEXT_OBJ_INIT_REST;
context_stack_allocation = PARSER_OBJ_INIT_REST_CONTEXT_STACK_ALLOCATION;
}
uint32_t context_size = (uint32_t) (stack_top_p + context_stack_allocation - VM_LAST_CONTEXT_END ());
stack_top_p += context_stack_allocation;
VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, context_size);
stack_top_p[-1] = VM_CREATE_CONTEXT (context_type, context_size);
stack_top_p[-2] = left_value;
if (context_type == VM_CONTEXT_OBJ_INIT_REST)
{
stack_top_p[-3] = ecma_make_object_value (ecma_op_new_array_object (0));
}
continue;
}
case VM_OC_INITIALIZER_PUSH_REST:
case VM_OC_OBJ_INIT_CONTEXT_END:
{
if (!ecma_op_require_object_coercible (stack_top_p[-1]))
JERRY_ASSERT (stack_top_p == VM_LAST_CONTEXT_END ());
uint32_t context_stack_allocation = PARSER_OBJ_INIT_CONTEXT_STACK_ALLOCATION;
if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_OBJ_INIT_REST)
{
context_stack_allocation = PARSER_OBJ_INIT_REST_CONTEXT_STACK_ALLOCATION;
}
stack_top_p = vm_stack_context_abort_variable_length (frame_ctx_p,
stack_top_p,
context_stack_allocation);
continue;
}
case VM_OC_OBJ_INIT_PUSH_REST:
{
ecma_value_t *last_context_end_p = VM_LAST_CONTEXT_END ();
if (!ecma_op_require_object_coercible (last_context_end_p[-2]))
{
result = ECMA_VALUE_ERROR;
goto error;
@@ -2428,16 +2503,18 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
ecma_object_t *result_object_p = ecma_create_object (prototype_p, 0, ECMA_OBJECT_TYPE_GENERAL);
left_value = ecma_make_object_value (result_object_p);
result = opfunc_copy_data_properties (left_value, stack_top_p[-1], stack_top_p[-2]);
result = opfunc_copy_data_properties (left_value, last_context_end_p[-2], last_context_end_p[-3]);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
ecma_free_value (stack_top_p[-2]);
stack_top_p[-2] = stack_top_p[-1];
stack_top_p[-1] = left_value;
ecma_free_value (last_context_end_p[-3]);
last_context_end_p[-3] = last_context_end_p[-2];
last_context_end_p[-2] = ECMA_VALUE_UNDEFINED;
*stack_top_p++ = left_value;
continue;
}
case VM_OC_INITIALIZER_PUSH_NAME:
@@ -2456,7 +2533,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
left_value = ecma_make_string_value (property_key);
}
ecma_object_t *array_obj_p = ecma_get_object_from_value (stack_top_p[-2]);
ecma_value_t *last_context_end_p = VM_LAST_CONTEXT_END ();
ecma_object_t *array_obj_p = ecma_get_object_from_value (last_context_end_p[-3]);
JERRY_ASSERT (ecma_get_object_type (array_obj_p) == ECMA_OBJECT_TYPE_ARRAY);
ecma_extended_object_t *ext_array_obj_p = (ecma_extended_object_t *) array_obj_p;
@@ -2465,7 +2543,21 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
}
case VM_OC_INITIALIZER_PUSH_PROP:
{
result = vm_op_get_value (stack_top_p[-1], left_value);
ecma_value_t *last_context_end_p = VM_LAST_CONTEXT_END ();
right_value = last_context_end_p[-2];
if (opcode == CBC_EXT_INITIALIZER_PUSH_PROP)
{
left_value = *last_context_end_p++;
while (last_context_end_p < stack_top_p)
{
last_context_end_p[-1] = *last_context_end_p;
last_context_end_p++;
}
stack_top_p--;
}
result = vm_op_get_value (right_value, left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
@@ -2475,21 +2567,6 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
*stack_top_p++ = result;
goto free_left_value;
}
case VM_OC_MOVE:
{
JERRY_ASSERT (opcode >= CBC_EXT_MOVE && opcode <= CBC_EXT_MOVE_3);
const uint8_t index = (uint8_t) (1 + (opcode - CBC_EXT_MOVE));
ecma_value_t element = stack_top_p[-index];
for (int32_t i = -index; i < -1; i++)
{
stack_top_p[i] = stack_top_p[i + 1];
}
stack_top_p[-1] = element;
continue;
}
case VM_OC_SPREAD_ARGUMENTS:
{
uint8_t arguments_list_len = *byte_code_p++;