From 12211d8aaa76716370d0151c4fa9a15f866a5e3f Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Tue, 26 Nov 2019 15:47:36 +0100 Subject: [PATCH] Fix the order of the function arguments for spread operation (#3369) JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- jerry-core/parser/js/js-parser-expr.c | 20 ++++++-------------- jerry-core/vm/opcodes.c | 11 +++++------ jerry-core/vm/opcodes.h | 2 +- jerry-core/vm/vm.c | 6 ++++-- tests/jerry/es2015/argument-spread.js | 11 +++++++++++ 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index e22ecbcc3..7b4945386 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -1662,7 +1662,7 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ lexer_next_token (context_p); #if ENABLED (JERRY_ES2015) - uint32_t spread_arguments = 0; + bool has_spread_element = false; #endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_RIGHT_PAREN) @@ -1675,23 +1675,17 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ } #if ENABLED (JERRY_ES2015) - lexer_token_type_t type = context_p->token.type; - if (type == LEXER_THREE_DOTS) + if (context_p->token.type == LEXER_THREE_DOTS) { - spread_arguments++; + has_spread_element = true; + call_arguments++; + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SPREAD_ELEMENT); lexer_next_token (context_p); } #endif /* ENABLED (JERRY_ES2015) */ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); -#if ENABLED (JERRY_ES2015) - if (type == LEXER_THREE_DOTS) - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SPREAD_ELEMENT); - } -#endif /* ENABLED (JERRY_ES2015) */ - if (context_p->token.type != LEXER_COMMA) { break; @@ -1732,7 +1726,7 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; } - if (spread_arguments != 0) + if (has_spread_element) { uint16_t spread_opcode; @@ -1755,8 +1749,6 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ spread_opcode = CBC_EXT_SPREAD_SUPER_CALL; } - /* Manually adjust stack usage */ - PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, spread_arguments); parser_emit_cbc_ext_call (context_p, spread_opcode, call_arguments); continue; } diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index f50cf3a43..a0c5de478 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -385,15 +385,14 @@ opfunc_append_to_spread_array (ecma_value_t *stack_top_p, /**< current stack top * pointer to the ecma-collection with the spreaded arguments, otherwise */ JERRY_ATTR_NOINLINE ecma_collection_t * -opfunc_spread_arguments (ecma_value_t **stack_top_p, /**< [out] pointer to the current stack top */ +opfunc_spread_arguments (ecma_value_t *stack_top_p, /**< pointer to the current stack top */ uint8_t arguments_list_len) /**< number of arguments */ { - ecma_value_t *curr_stack_top_p = *stack_top_p; ecma_collection_t *buff_p = ecma_new_collection (); for (uint32_t i = 0; i < arguments_list_len; i++) { - ecma_value_t arg = *(--curr_stack_top_p); + ecma_value_t arg = *stack_top_p++; if (arg != ECMA_VALUE_SPREAD_ELEMENT) { @@ -402,7 +401,8 @@ opfunc_spread_arguments (ecma_value_t **stack_top_p, /**< [out] pointer to the c } ecma_value_t ret_value = ECMA_VALUE_ERROR; - ecma_value_t spread_value = *(--curr_stack_top_p); + ecma_value_t spread_value = *stack_top_p++; + i++; ecma_value_t iterator = ecma_op_get_iterator (spread_value, ECMA_VALUE_EMPTY); @@ -443,7 +443,7 @@ opfunc_spread_arguments (ecma_value_t **stack_top_p, /**< [out] pointer to the c { for (uint32_t k = i + 1; k < arguments_list_len; k++) { - ecma_free_value (*(--curr_stack_top_p)); + ecma_free_value (*(++stack_top_p)); } ecma_collection_free (buff_p); @@ -452,7 +452,6 @@ opfunc_spread_arguments (ecma_value_t **stack_top_p, /**< [out] pointer to the c } } - *stack_top_p = curr_stack_top_p; return buff_p; } /* opfunc_spread_arguments */ #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index a4f46dc06..60a19e4b0 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -106,7 +106,7 @@ opfunc_append_array (ecma_value_t *stack_top_p, uint16_t values_length); #if ENABLED (JERRY_ES2015) ecma_collection_t * -opfunc_spread_arguments (ecma_value_t **stack_top_p, uint8_t argument_list_len); +opfunc_spread_arguments (ecma_value_t *stack_top_p, uint8_t argument_list_len); #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 5e544eff5..ad0f6af58 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -1585,7 +1585,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ if (opcode >= CBC_EXT_SPREAD_SUPER_CALL) { - ecma_collection_t *arguments_p = opfunc_spread_arguments (&stack_top_p, arguments_list_len); + stack_top_p -= arguments_list_len; + ecma_collection_t *arguments_p = opfunc_spread_arguments (stack_top_p, arguments_list_len); if (JERRY_UNLIKELY (arguments_p == NULL)) { @@ -2043,8 +2044,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ case VM_OC_SPREAD_ARGUMENTS: { uint8_t arguments_list_len = *byte_code_p++; + stack_top_p -= arguments_list_len; - ecma_collection_t *arguments_p = opfunc_spread_arguments (&stack_top_p, arguments_list_len); + ecma_collection_t *arguments_p = opfunc_spread_arguments (stack_top_p, arguments_list_len); if (JERRY_UNLIKELY (arguments_p == NULL)) { diff --git a/tests/jerry/es2015/argument-spread.js b/tests/jerry/es2015/argument-spread.js index c0bf7eb64..3d1599547 100644 --- a/tests/jerry/es2015/argument-spread.js +++ b/tests/jerry/es2015/argument-spread.js @@ -98,3 +98,14 @@ var array = new MyArray(1, 2, 3); assertArrayEqual(array, [1,2,3]); assert(array instanceof MyArray); assert(array instanceof Array); + +function argumentOrderTest() { + var result = [] + for (i = 0; i < arguments.length; i++) { + result.push(arguments[i]); + } + + return result; +} + +assertArrayEqual(argumentOrderTest(1, 2, ...[3, 4]), [1, 2, 3, 4]);