From d953fbb7bef914da5db5ef7a2f3a54d519f8bd8a Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Wed, 8 Jun 2016 06:29:14 -0700 Subject: [PATCH] Branch opcodes have no result and either they have a stack argument or no arguments at all. To improve the performance, the branch argument flag is changed into a get argument type which eliminates a flag check for all executed opcodes. Furthermore branch opcodes skip the put result phase by changing the "break" to "continue" statements. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/parser/js/byte-code.h | 30 ++--- jerry-core/vm/vm.c | 183 ++++++++++++++++--------------- jerry-core/vm/vm.h | 18 ++- 3 files changed, 115 insertions(+), 116 deletions(-) diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index fbb2e7f99..d21bafd38 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -173,19 +173,19 @@ #define CBC_FORWARD_BRANCH(name, stack, vm_oc) \ CBC_OPCODE (name, CBC_HAS_BRANCH_ARG | CBC_FORWARD_BRANCH_ARG, stack, \ - (vm_oc) | VM_OC_HAS_BRANCH_ARG) \ + (vm_oc) | VM_OC_GET_BRANCH) \ CBC_OPCODE (name ## _2, CBC_HAS_BRANCH_ARG | CBC_FORWARD_BRANCH_ARG, stack, \ - (vm_oc) | VM_OC_HAS_BRANCH_ARG) \ + (vm_oc) | VM_OC_GET_BRANCH) \ CBC_OPCODE (name ## _3, CBC_HAS_BRANCH_ARG | CBC_FORWARD_BRANCH_ARG, stack, \ - (vm_oc) | VM_OC_HAS_BRANCH_ARG) + (vm_oc) | VM_OC_GET_BRANCH) #define CBC_BACKWARD_BRANCH(name, stack, vm_oc) \ CBC_OPCODE (name, CBC_HAS_BRANCH_ARG, stack, \ - (vm_oc) | VM_OC_HAS_BRANCH_ARG | VM_OC_BACKWARD_BRANCH) \ + (vm_oc) | VM_OC_GET_BRANCH | VM_OC_BACKWARD_BRANCH) \ CBC_OPCODE (name ## _2, CBC_HAS_BRANCH_ARG, stack, \ - (vm_oc) | VM_OC_HAS_BRANCH_ARG | VM_OC_BACKWARD_BRANCH) \ + (vm_oc) | VM_OC_GET_BRANCH | VM_OC_BACKWARD_BRANCH) \ CBC_OPCODE (name ## _3, CBC_HAS_BRANCH_ARG, stack, \ - (vm_oc) | VM_OC_HAS_BRANCH_ARG | VM_OC_BACKWARD_BRANCH) + (vm_oc) | VM_OC_GET_BRANCH | VM_OC_BACKWARD_BRANCH) #define CBC_BRANCH_OFFSET_LENGTH(opcode) \ ((opcode) & 0x3) @@ -221,19 +221,19 @@ CBC_OPCODE (CBC_POP_BLOCK, CBC_NO_FLAG, -1, \ VM_OC_POP_BLOCK | VM_OC_PUT_BLOCK) \ CBC_FORWARD_BRANCH (CBC_BRANCH_IF_TRUE_FORWARD, -1, \ - VM_OC_BRANCH_IF_TRUE | VM_OC_GET_STACK) \ + VM_OC_BRANCH_IF_TRUE) \ CBC_OPCODE (CBC_THROW, CBC_NO_FLAG, -1, \ VM_OC_THROW | VM_OC_GET_STACK) \ CBC_BACKWARD_BRANCH (CBC_BRANCH_IF_TRUE_BACKWARD, -1, \ - VM_OC_BRANCH_IF_TRUE | VM_OC_GET_STACK) \ + VM_OC_BRANCH_IF_TRUE) \ CBC_OPCODE (CBC_CONTEXT_END, CBC_NO_FLAG, 0, \ VM_OC_CONTEXT_END) \ CBC_FORWARD_BRANCH (CBC_BRANCH_IF_FALSE_FORWARD, -1, \ - VM_OC_BRANCH_IF_FALSE | VM_OC_GET_STACK) \ + VM_OC_BRANCH_IF_FALSE) \ CBC_OPCODE (CBC_CREATE_OBJECT, CBC_NO_FLAG, 1, \ VM_OC_PUSH_OBJECT | VM_OC_PUT_STACK) \ CBC_BACKWARD_BRANCH (CBC_BRANCH_IF_FALSE_BACKWARD, -1, \ - VM_OC_BRANCH_IF_FALSE | VM_OC_GET_STACK) \ + VM_OC_BRANCH_IF_FALSE) \ CBC_OPCODE (CBC_SET_PROPERTY, CBC_HAS_LITERAL_ARG, -1, \ VM_OC_SET_PROPERTY | VM_OC_GET_STACK_LITERAL) \ CBC_FORWARD_BRANCH (CBC_JUMP_FORWARD_EXIT_CONTEXT, 0, \ @@ -241,15 +241,15 @@ CBC_OPCODE (CBC_CREATE_ARRAY, CBC_NO_FLAG, 1, \ VM_OC_PUSH_ARRAY | VM_OC_PUT_STACK) \ CBC_FORWARD_BRANCH (CBC_BRANCH_IF_LOGICAL_TRUE, -1, \ - VM_OC_BRANCH_IF_LOGICAL_TRUE | VM_OC_GET_STACK) \ + VM_OC_BRANCH_IF_LOGICAL_TRUE) \ CBC_OPCODE (CBC_ARRAY_APPEND, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ VM_OC_APPEND_ARRAY) \ CBC_FORWARD_BRANCH (CBC_BRANCH_IF_LOGICAL_FALSE, -1, \ - VM_OC_BRANCH_IF_LOGICAL_FALSE | VM_OC_GET_STACK) \ + VM_OC_BRANCH_IF_LOGICAL_FALSE) \ CBC_OPCODE (CBC_PUSH_ELISION, CBC_NO_FLAG, 1, \ VM_OC_PUSH_ELISON | VM_OC_PUT_STACK) \ CBC_FORWARD_BRANCH (CBC_BRANCH_IF_STRICT_EQUAL, -1, \ - VM_OC_BRANCH_IF_STRICT_EQUAL | VM_OC_GET_STACK) \ + VM_OC_BRANCH_IF_STRICT_EQUAL) \ \ /* Basic opcodes. */ \ CBC_OPCODE (CBC_PUSH_LITERAL, CBC_HAS_LITERAL_ARG, 1, \ @@ -515,11 +515,11 @@ CBC_OPCODE (CBC_EXT_NOP, CBC_NO_FLAG, 0, \ VM_OC_NONE) \ CBC_FORWARD_BRANCH (CBC_EXT_WITH_CREATE_CONTEXT, \ - -1 + PARSER_WITH_CONTEXT_STACK_ALLOCATION, VM_OC_WITH | VM_OC_GET_STACK) \ + -1 + PARSER_WITH_CONTEXT_STACK_ALLOCATION, VM_OC_WITH) \ CBC_OPCODE (CBC_EXT_FOR_IN_GET_NEXT, CBC_NO_FLAG, 1, \ VM_OC_FOR_IN_GET_NEXT | VM_OC_PUT_STACK) \ CBC_FORWARD_BRANCH (CBC_EXT_FOR_IN_CREATE_CONTEXT, \ - -1 + PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION, VM_OC_FOR_IN_CREATE_CONTEXT | VM_OC_GET_STACK) \ + -1 + PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION, VM_OC_FOR_IN_CREATE_CONTEXT) \ CBC_OPCODE (CBC_EXT_SET_GETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ VM_OC_SET_GETTER | VM_OC_GET_LITERAL_LITERAL) \ CBC_BACKWARD_BRANCH (CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT, 0, \ diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index b2a0062fe..98f75c672 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -742,11 +742,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ while (true) { uint8_t *byte_code_start_p = byte_code_p; - uint8_t opcode; - uint32_t opcode_data; + uint8_t opcode = *byte_code_p++; + uint32_t opcode_data = opcode; - opcode = *byte_code_p++; - opcode_data = opcode; if (opcode == CBC_EXT_OPCODE) { opcode = *byte_code_p++; @@ -755,25 +753,82 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ opcode_data = vm_decode_table[opcode_data]; - if (opcode_data & VM_OC_HAS_BRANCH_ARG) + left_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + right_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + + uint32_t operands = VM_OC_GET_ARGS_INDEX (opcode_data); + + if (operands >= VM_OC_GET_LITERAL) + { + uint16_t literal_index; + READ_LITERAL_INDEX (literal_index); + READ_LITERAL (literal_index, left_value); + + if (operands != VM_OC_GET_LITERAL) + { + switch (operands) + { + case VM_OC_GET_LITERAL_LITERAL: + { + uint16_t literal_index; + READ_LITERAL_INDEX (literal_index); + READ_LITERAL (literal_index, right_value); + break; + } + case VM_OC_GET_STACK_LITERAL: + { + JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); + right_value = left_value; + left_value = *(--stack_top_p); + break; + } + default: + { + JERRY_ASSERT (operands == VM_OC_GET_THIS_LITERAL); + right_value = left_value; + left_value = ecma_copy_value (frame_ctx_p->this_binding); + break; + } + } + } + } + else if (operands >= VM_OC_GET_STACK) + { + JERRY_ASSERT (operands == VM_OC_GET_STACK + || operands == VM_OC_GET_STACK_STACK); + + JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); + left_value = *(--stack_top_p); + + if (operands == VM_OC_GET_STACK_STACK) + { + JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); + right_value = left_value; + left_value = *(--stack_top_p); + } + } + else if (operands == VM_OC_GET_BRANCH) { branch_offset = 0; + switch (CBC_BRANCH_OFFSET_LENGTH (opcode)) { + case 1: + { + branch_offset = *(byte_code_p++); + break; + } case 3: { branch_offset = *(byte_code_p++); /* FALLTHRU */ } - case 2: - { - branch_offset <<= 8; - branch_offset |= *(byte_code_p++); - /* FALLTHRU */ - } default: { - JERRY_ASSERT (CBC_BRANCH_OFFSET_LENGTH (opcode) > 0); + JERRY_ASSERT (CBC_BRANCH_OFFSET_LENGTH (opcode) == 2); + + branch_offset <<= 8; + branch_offset |= *(byte_code_p++); branch_offset <<= 8; branch_offset |= *(byte_code_p++); break; @@ -786,66 +841,6 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } } - left_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); - right_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); - - if (VM_OC_HAS_GET_ARGS (opcode_data)) - { - uint32_t operands = VM_OC_GET_ARGS_INDEX (opcode_data); - - if (operands >= VM_OC_GET_LITERAL) - { - uint16_t literal_index; - READ_LITERAL_INDEX (literal_index); - READ_LITERAL (literal_index, - left_value); - - if (operands != VM_OC_GET_LITERAL) - { - switch (operands) - { - case VM_OC_GET_LITERAL_LITERAL: - { - uint16_t literal_index; - READ_LITERAL_INDEX (literal_index); - READ_LITERAL (literal_index, - right_value); - break; - } - case VM_OC_GET_STACK_LITERAL: - { - JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); - right_value = left_value; - left_value = *(--stack_top_p); - break; - } - default: - { - JERRY_ASSERT (operands == VM_OC_GET_THIS_LITERAL); - right_value = left_value; - left_value = ecma_copy_value (frame_ctx_p->this_binding); - break; - } - } - } - } - else - { - JERRY_ASSERT (operands == VM_OC_GET_STACK - || operands == VM_OC_GET_STACK_STACK); - - JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); - left_value = *(--stack_top_p); - - if (operands == VM_OC_GET_STACK_STACK) - { - JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); - right_value = left_value; - left_value = *(--stack_top_p); - } - } - } - switch (VM_OC_GROUP_GET_INDEX (opcode_data)) { case VM_OC_NONE: @@ -883,8 +878,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ left_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); READ_LITERAL_INDEX (literal_index); - READ_LITERAL (literal_index, - left_value); + READ_LITERAL (literal_index, left_value); *(stack_top_p++) = right_value; *(stack_top_p++) = left_value; @@ -1464,18 +1458,21 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ case VM_OC_JUMP: { byte_code_p = byte_code_start_p + branch_offset; - break; + continue; } case VM_OC_BRANCH_IF_STRICT_EQUAL: { + ecma_value_t value = *(--stack_top_p); + JERRY_ASSERT (stack_top_p > frame_ctx_p->registers_p + register_end); - if (ecma_op_strict_equality_compare (left_value, stack_top_p[-1])) + if (ecma_op_strict_equality_compare (value, stack_top_p[-1])) { byte_code_p = byte_code_start_p + branch_offset; ecma_free_value (*--stack_top_p); } - break; + ecma_free_value (value); + continue; } case VM_OC_BRANCH_IF_TRUE: case VM_OC_BRANCH_IF_FALSE: @@ -1483,8 +1480,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ case VM_OC_BRANCH_IF_LOGICAL_FALSE: { uint32_t opcode_flags = VM_OC_GROUP_GET_INDEX (opcode_data) - VM_OC_BRANCH_IF_TRUE; + ecma_value_t value = *(--stack_top_p); - bool boolean_value = ecma_op_to_boolean (left_value); + bool boolean_value = ecma_op_to_boolean (value); if (opcode_flags & VM_OC_BRANCH_IF_FALSE_FLAG) { @@ -1496,13 +1494,13 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ byte_code_p = byte_code_start_p + branch_offset; if (opcode_flags & VM_OC_LOGICAL_BRANCH_FLAG) { - /* "Push" the left_value back to the stack. */ + /* "Push" the value back to the stack. */ ++stack_top_p; continue; } } - ecma_fast_free_value (left_value); + ecma_fast_free_value (value); continue; } case VM_OC_PLUS: @@ -1827,6 +1825,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_WITH: { + ecma_value_t value = *(--stack_top_p); ecma_object_t *object_p; ecma_object_t *with_env_p; @@ -1834,7 +1833,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); - result = ecma_op_to_object (left_value); + result = ecma_op_to_object (value); + ecma_free_value (value); if (ecma_is_value_error (result)) { @@ -1856,19 +1856,22 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ stack_top_p[-2] = ecma_make_object_value (frame_ctx_p->lex_env_p); frame_ctx_p->lex_env_p = with_env_p; - break; + continue; } case VM_OC_FOR_IN_CREATE_CONTEXT: { + ecma_value_t value = *(--stack_top_p); + JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); ecma_value_t expr_obj_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); - ecma_collection_header_t *header_p = opfunc_for_in (left_value, &expr_obj_value); + ecma_collection_header_t *header_p = opfunc_for_in (value, &expr_obj_value); + ecma_free_value (value); if (header_p == NULL) { byte_code_p = byte_code_start_p + branch_offset; - break; + continue; } branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p); @@ -1880,7 +1883,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ stack_top_p[-3] = expr_obj_value; ecma_dealloc_collection_header (header_p); - break; + continue; } case VM_OC_FOR_IN_GET_NEXT: { @@ -1930,7 +1933,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } } - break; + continue; } case VM_OC_TRY: { @@ -1943,7 +1946,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ stack_top_p += PARSER_TRY_CONTEXT_STACK_ALLOCATION; stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_TRY, branch_offset); - break; + continue; } case VM_OC_CATCH: { @@ -1952,7 +1955,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_TRY); byte_code_p = byte_code_start_p + branch_offset; - break; + continue; } case VM_OC_FINALLY: { @@ -1971,7 +1974,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_FINALLY_JUMP, branch_offset); stack_top_p[-2] = (ecma_value_t) branch_offset; - break; + continue; } case VM_OC_CONTEXT_END: { @@ -2050,7 +2053,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); - break; + continue; } default: { diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index 41aacb4a8..61b50b1ec 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -42,11 +42,6 @@ * stack, etc.) */ -/** - * Opcode has branch argument - */ -#define VM_OC_HAS_BRANCH_ARG 0x8000 - /** * Branch argument is a backward branch */ @@ -83,14 +78,15 @@ typedef enum { VM_OC_GET_NONE = VM_OC_GET_ARGS_CREATE_INDEX (0), /**< do nothing */ - VM_OC_GET_STACK = VM_OC_GET_ARGS_CREATE_INDEX (1), /**< pop one element from the stack */ - VM_OC_GET_STACK_STACK = VM_OC_GET_ARGS_CREATE_INDEX (2), /**< pop two elements from the stack */ + VM_OC_GET_BRANCH = VM_OC_GET_ARGS_CREATE_INDEX (1), /**< branch argument */ + VM_OC_GET_STACK = VM_OC_GET_ARGS_CREATE_INDEX (2), /**< pop one element from the stack */ + VM_OC_GET_STACK_STACK = VM_OC_GET_ARGS_CREATE_INDEX (3), /**< pop two elements from the stack */ - VM_OC_GET_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (3), /**< resolve literal */ - VM_OC_GET_LITERAL_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (4), /**< resolve two literals */ - VM_OC_GET_STACK_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (5), /**< pop one element from the stack + VM_OC_GET_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (4), /**< resolve literal */ + VM_OC_GET_LITERAL_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (5), /**< resolve two literals */ + VM_OC_GET_STACK_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (6), /**< pop one element from the stack * and resolve a literal */ - VM_OC_GET_THIS_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (6), /**< get this and resolve a literal */ + VM_OC_GET_THIS_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (7), /**< get this and resolve a literal */ } vm_oc_get_types; /**