From 132de45c0bd4ada80e35bad3e5c59e922c10fd94 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Mon, 2 Dec 2019 12:37:13 +0100 Subject: [PATCH] Remove CBC_EXT_CONTINUE_EXEC opcode. (#3378) There is no need for a specific opcode after yield because the return and throw commands can be redirected to fake byte code sequences. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/ecma/base/ecma-globals.h | 10 ----- .../ecma-builtin-generator-prototype.c | 37 +++++++++++++++- jerry-core/include/jerryscript-snapshot.h | 2 +- jerry-core/jcontext/jcontext.h | 4 +- jerry-core/parser/js/byte-code.h | 14 +++--- jerry-core/parser/js/js-parser-expr.c | 1 - jerry-core/parser/js/js-parser.c | 2 - jerry-core/vm/opcodes.c | 4 -- jerry-core/vm/vm-defines.h | 4 +- jerry-core/vm/vm-stack.c | 4 +- jerry-core/vm/vm.c | 44 +++++++------------ jerry-core/vm/vm.h | 6 +-- tests/unit-core/test-snapshot.c | 2 +- 13 files changed, 69 insertions(+), 65 deletions(-) diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 62b5fdf06..011e96baf 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -1769,16 +1769,6 @@ typedef enum #define ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED(extra_info) \ (!((extra_info) & (ECMA_EXECUTABLE_OBJECT_COMPLETED | ECMA_EXECUTABLE_OBJECT_RUNNING))) -/** - * Executable (e.g. generator, async) object flags. - */ -typedef enum -{ - ECMA_GENERATOR_NEXT, /**< generator should continue its execution */ - ECMA_GENERATOR_RETURN, /**< generator should perform a return operation */ - ECMA_GENERATOR_THROW, /**< generator should perform a throw operation */ -} ecma_generator_yield_mode_t; - #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c index c532a67b8..43a2b4ba2 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c @@ -40,6 +40,32 @@ * @{ */ +/** + * Generator resume execution flags. + */ +typedef enum +{ + ECMA_GENERATOR_NEXT, /**< generator should continue its execution */ + ECMA_GENERATOR_RETURN, /**< generator should perform a return operation */ + ECMA_GENERATOR_THROW, /**< generator should perform a throw operation */ +} ecma_generator_resume_mode_t; + +/** + * Byte code sequence which returns from the generator. + */ +static const uint8_t ecma_builtin_generator_prototype_return[2] = +{ + CBC_EXT_OPCODE, CBC_EXT_RETURN +}; + +/** + * Byte code sequence which throws an exception. + */ +static const uint8_t ecma_builtin_generator_prototype_throw[1] = +{ + CBC_THROW +}; + /** * Helper function for next / return / throw * @@ -49,7 +75,7 @@ static ecma_value_t ecma_builtin_generator_prototype_object_do (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg, /**< argument */ - uint8_t yield_mode) /**< yield mode */ + ecma_generator_resume_mode_t resume_mode) /**< resume mode */ { vm_executable_object_t *executable_object_p = NULL; @@ -83,7 +109,14 @@ ecma_builtin_generator_prototype_object_do (ecma_value_t this_arg, /**< this arg return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); } - executable_object_p->frame_ctx.call_operation = yield_mode; + if (resume_mode == ECMA_GENERATOR_RETURN) + { + executable_object_p->frame_ctx.byte_code_p = ecma_builtin_generator_prototype_return; + } + else if (resume_mode == ECMA_GENERATOR_THROW) + { + executable_object_p->frame_ctx.byte_code_p = ecma_builtin_generator_prototype_throw; + } ecma_value_t value = opfunc_resume_executable_object (executable_object_p, arg); diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index d3482abde..a79745879 100644 --- a/jerry-core/include/jerryscript-snapshot.h +++ b/jerry-core/include/jerryscript-snapshot.h @@ -30,7 +30,7 @@ extern "C" /** * Jerry snapshot format version. */ -#define JERRY_SNAPSHOT_VERSION (32u) +#define JERRY_SNAPSHOT_VERSION (33u) /** * Flags for jerry_generate_snapshot and jerry_generate_function_snapshot. diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 0c7e4abc0..b974ecf66 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -195,8 +195,8 @@ struct jerry_context_t jerry_debugger_transport_header_t *debugger_transport_header_p; /**< head of transport protocol chain */ uint8_t *debugger_send_buffer_payload_p; /**< start where the outgoing message can be written */ vm_frame_ctx_t *debugger_stop_context; /**< stop only if the current context is equal to this context */ - uint8_t *debugger_exception_byte_code_p; /**< Location of the currently executed byte code if an - * error occours while the vm_loop is suspended */ + const uint8_t *debugger_exception_byte_code_p; /**< Location of the currently executed byte code if an + * error occours while the vm_loop is suspended */ jmem_cpointer_t debugger_byte_code_free_head; /**< head of byte code free linked list */ jmem_cpointer_t debugger_byte_code_free_tail; /**< tail of byte code free linked list */ uint32_t debugger_flags; /**< debugger flags */ diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 14de8e89c..506f2c30f 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -321,11 +321,11 @@ CBC_OPCODE (CBC_SET_BYTECODE_PTR, CBC_NO_FLAG, 0, \ VM_OC_NONE) \ CBC_OPCODE (CBC_RETURN, CBC_NO_FLAG, -1, \ - VM_OC_RET | VM_OC_GET_STACK) \ + VM_OC_RETURN | VM_OC_GET_STACK) \ CBC_OPCODE (CBC_RETURN_WITH_BLOCK, CBC_NO_FLAG, 0, \ - VM_OC_RET) \ + VM_OC_RETURN) \ CBC_OPCODE (CBC_RETURN_WITH_LITERAL, CBC_HAS_LITERAL_ARG, 0, \ - VM_OC_RET | VM_OC_GET_LITERAL) \ + VM_OC_RETURN | VM_OC_GET_LITERAL) \ CBC_OPCODE (CBC_SET_LITERAL_PROPERTY, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ VM_OC_SET_PROPERTY | VM_OC_NON_STATIC_FLAG | VM_OC_GET_LITERAL_LITERAL) \ CBC_OPCODE (CBC_BREAKPOINT_ENABLED, CBC_NO_FLAG, 0, \ @@ -654,12 +654,12 @@ VM_OC_INITIALIZER_PUSH_PROP | VM_OC_GET_LITERAL) \ CBC_OPCODE (CBC_EXT_SPREAD_NEW, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ VM_OC_SPREAD_ARGUMENTS | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_CREATE_GENERATOR, CBC_NO_FLAG, 0, \ + CBC_OPCODE (CBC_EXT_CREATE_GENERATOR, CBC_NO_FLAG, 1, \ VM_OC_CREATE_GENERATOR) \ - CBC_OPCODE (CBC_EXT_YIELD, CBC_NO_FLAG, -1, \ + CBC_OPCODE (CBC_EXT_YIELD, CBC_NO_FLAG, 0, \ VM_OC_YIELD | VM_OC_GET_STACK) \ - CBC_OPCODE (CBC_EXT_CONTINUE_EXEC, CBC_NO_FLAG, 1, \ - VM_OC_CONTINUE_EXEC) \ + CBC_OPCODE (CBC_EXT_RETURN, CBC_NO_FLAG, -1, \ + VM_OC_EXT_RETURN | VM_OC_GET_STACK) \ \ /* Last opcode (not a real opcode). */ \ CBC_OPCODE (CBC_EXT_END, CBC_NO_FLAG, 0, \ diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 72a1dbd22..b5b8b3fb8 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -1573,7 +1573,6 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ } parser_emit_cbc_ext (context_p, CBC_EXT_YIELD); - parser_emit_cbc_ext (context_p, CBC_EXT_CONTINUE_EXEC); return (context_p->token.type != LEXER_RIGHT_PAREN && context_p->token.type != LEXER_COMMA); diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 85c795563..de18f0c37 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1636,7 +1636,6 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) { parser_emit_cbc_ext (context_p, CBC_EXT_CREATE_GENERATOR); - parser_emit_cbc_ext (context_p, CBC_EXT_CONTINUE_EXEC); parser_emit_cbc (context_p, CBC_POP); } @@ -1810,7 +1809,6 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) { parser_emit_cbc_ext (context_p, CBC_EXT_CREATE_GENERATOR); - parser_emit_cbc_ext (context_p, CBC_EXT_CONTINUE_EXEC); parser_emit_cbc (context_p, CBC_POP); } diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 2a0bf04ee..fdd9fc4c6 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -654,10 +654,6 @@ opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, /* ecma_ref_if_object (*register_p++); } - uint8_t *byte_code_p = executable_object_p->frame_ctx.byte_code_p; - - JERRY_ASSERT (byte_code_p[0] == CBC_EXT_OPCODE && byte_code_p[1] == CBC_EXT_CONTINUE_EXEC); - *register_p++ = ecma_copy_value (value); executable_object_p->frame_ctx.stack_top_p = register_p; diff --git a/jerry-core/vm/vm-defines.h b/jerry-core/vm/vm-defines.h index 15d4c1a25..f328fcff8 100644 --- a/jerry-core/vm/vm-defines.h +++ b/jerry-core/vm/vm-defines.h @@ -41,8 +41,8 @@ typedef struct vm_frame_ctx_t { const ecma_compiled_code_t *bytecode_header_p; /**< currently executed byte-code data */ - uint8_t *byte_code_p; /**< current byte code pointer */ - uint8_t *byte_code_start_p; /**< byte code start pointer */ + const uint8_t *byte_code_p; /**< current byte code pointer */ + const uint8_t *byte_code_start_p; /**< byte code start pointer */ ecma_value_t *stack_top_p; /**< stack top pointer */ ecma_value_t *literal_start_p; /**< literal list start pointer */ ecma_object_t *lex_env_p; /**< current lexical environment */ diff --git a/jerry-core/vm/vm-stack.c b/jerry-core/vm/vm-stack.c index b4e1b6d85..5f0beecd3 100644 --- a/jerry-core/vm/vm-stack.c +++ b/jerry-core/vm/vm-stack.c @@ -119,7 +119,7 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ * @return branch offset */ static uint32_t -vm_decode_branch_offset (uint8_t *branch_offset_p, /**< start offset of byte code */ +vm_decode_branch_offset (const uint8_t *branch_offset_p, /**< start offset of byte code */ uint32_t length) /**< length of the branch */ { uint32_t branch_offset = *branch_offset_p; @@ -180,7 +180,7 @@ vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ context_type = VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]); if (context_type == VM_CONTEXT_TRY || context_type == VM_CONTEXT_CATCH) { - uint8_t *byte_code_p; + const uint8_t *byte_code_p; uint32_t branch_offset_length; uint32_t branch_offset; diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index b2bb619e5..a5019733d 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -477,7 +477,7 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (frame_ctx_p->call_operation == VM_EXEC_SUPER_CALL); JERRY_ASSERT (frame_ctx_p->byte_code_p[0] == CBC_EXT_OPCODE); - uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 3; + const uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 3; uint8_t opcode = byte_code_p[-2]; uint32_t arguments_list_len; @@ -667,7 +667,7 @@ vm_spread_operation (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ static void opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { - uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1; + const uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1; uint8_t opcode = byte_code_p[-1]; uint32_t arguments_list_len; @@ -755,7 +755,7 @@ opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ static void opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { - uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1; + const uint8_t *byte_code_p = frame_ctx_p->byte_code_p + 1; uint8_t opcode = byte_code_p[-1]; unsigned int arguments_list_len; @@ -882,7 +882,7 @@ static void vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->bytecode_header_p; - uint8_t *byte_code_p = frame_ctx_p->byte_code_p; + const uint8_t *byte_code_p = frame_ctx_p->byte_code_p; uint16_t encoding_limit; uint16_t encoding_delta; uint16_t register_end; @@ -1120,7 +1120,7 @@ static ecma_value_t JERRY_ATTR_NOINLINE vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->bytecode_header_p; - uint8_t *byte_code_p = frame_ctx_p->byte_code_p; + const uint8_t *byte_code_p = frame_ctx_p->byte_code_p; ecma_value_t *literal_start_p = frame_ctx_p->literal_start_p; ecma_value_t *stack_top_p; @@ -1171,7 +1171,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ /* Internal loop for byte code execution. */ while (true) { - uint8_t *byte_code_start_p = byte_code_p; + const uint8_t *byte_code_start_p = byte_code_p; uint8_t opcode = *byte_code_p++; uint32_t opcode_data = opcode; @@ -2076,31 +2076,19 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ frame_ctx_p->stack_top_p = stack_top_p; return left_value; } - case VM_OC_CONTINUE_EXEC: + case VM_OC_EXT_RETURN: { - if (JERRY_UNLIKELY (frame_ctx_p->call_operation == ECMA_GENERATOR_RETURN)) + result = left_value; + left_value = ECMA_VALUE_UNDEFINED; + + ecma_value_t *stack_bottom_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth; + + while (stack_top_p > stack_bottom_p) { - ecma_value_t *stack_bottom_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth; - - result = *(--stack_top_p); - - while (stack_top_p > stack_bottom_p) - { - ecma_fast_free_value (*(--stack_top_p)); - } - - goto error; + ecma_fast_free_value (*(--stack_top_p)); } - if (JERRY_UNLIKELY (frame_ctx_p->call_operation == ECMA_GENERATOR_THROW)) - { - JERRY_CONTEXT (error_value) = *(--stack_top_p); - JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; - - result = ECMA_VALUE_ERROR; - goto error; - } - continue; + goto error; } #endif /* ENABLED (JERRY_ES2015) */ case VM_OC_PUSH_ELISON: @@ -2406,7 +2394,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ left_value = ECMA_VALUE_UNDEFINED; break; } - case VM_OC_RET: + case VM_OC_RETURN: { JERRY_ASSERT (opcode == CBC_RETURN || opcode == CBC_RETURN_WITH_BLOCK diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index 80496c2eb..47b4ed156 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -151,7 +151,7 @@ typedef enum VM_OC_ASSIGN_PROP, /**< assign property */ VM_OC_ASSIGN_PROP_THIS, /**< assign prop this */ - VM_OC_RET, /**< return */ + VM_OC_RETURN, /**< return */ VM_OC_THROW, /**< throw */ VM_OC_THROW_REFERENCE_ERROR, /**< throw reference error */ @@ -257,7 +257,7 @@ 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_CONTINUE_EXEC, /**< first byte code after a function is resumed */ + VM_OC_EXT_RETURN, /**< return which also clears the stack */ #endif /* ENABLED (JERRY_ES2015) */ VM_OC_NONE, /**< a special opcode for unsupported byte codes */ } vm_oc_types; @@ -310,7 +310,7 @@ 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_CONTINUE_EXEC = VM_OC_NONE, /**< first byte code after a function is resumed */ + VM_OC_EXT_RETURN = VM_OC_NONE, /**< return which also clears the stack */ #endif /* !ENABLED (JERRY_ES2015) */ VM_OC_UNUSED = VM_OC_NONE /**< placeholder if the list is empty */ diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index 2c5964875..530e4bbe8 100644 --- a/tests/unit-core/test-snapshot.c +++ b/tests/unit-core/test-snapshot.c @@ -223,7 +223,7 @@ main (void) /* Check the snapshot data. Unused bytes should be filled with zeroes */ const uint8_t expected_data[] = { - 0x4A, 0x52, 0x52, 0x59, 0x20, 0x00, 0x00, 0x00, + 0x4A, 0x52, 0x52, 0x59, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x01, 0x00,