diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index e7955ac4d4..f01c39263f 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -295,9 +295,9 @@ CBC_OPCODE (CBC_NEW, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ VM_OC_NEW | VM_OC_GET_BYTE | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_NEW0, CBC_NO_FLAG, 0, \ - VM_OC_NEW_N | VM_OC_PUT_STACK) \ + VM_OC_NEW | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_NEW1, CBC_NO_FLAG, -1, \ - VM_OC_NEW_N | VM_OC_PUT_STACK) \ + VM_OC_NEW | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_EVAL, CBC_NO_FLAG, 0, \ VM_OC_EVAL) \ CBC_OPCODE (CBC_DEFINE_VARS, CBC_HAS_LITERAL_ARG, 0, \ @@ -405,47 +405,47 @@ CBC_OPCODE (CBC_CALL_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -1, \ VM_OC_CALL | VM_OC_GET_BYTE | VM_OC_PUT_BLOCK) \ CBC_OPCODE (CBC_CALL_PROP, CBC_HAS_POP_STACK_BYTE_ARG, -3, \ - VM_OC_CALL_PROP | VM_OC_GET_BYTE) \ + VM_OC_CALL | VM_OC_GET_BYTE) \ CBC_OPCODE (CBC_CALL_PROP_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, -2, \ - VM_OC_CALL_PROP | VM_OC_GET_BYTE | VM_OC_PUT_STACK) \ + VM_OC_CALL | VM_OC_GET_BYTE | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_CALL_PROP_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -3, \ - VM_OC_CALL_PROP | VM_OC_GET_BYTE | VM_OC_PUT_BLOCK) \ + VM_OC_CALL | VM_OC_GET_BYTE | VM_OC_PUT_BLOCK) \ CBC_OPCODE (CBC_CALL0, CBC_NO_FLAG, -1, \ - VM_OC_CALL_N) \ + VM_OC_CALL) \ CBC_OPCODE (CBC_CALL0_PUSH_RESULT, CBC_NO_FLAG, 0, \ - VM_OC_CALL_N | VM_OC_PUT_STACK) \ + VM_OC_CALL | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_CALL0_BLOCK, CBC_NO_FLAG, -1, \ - VM_OC_CALL_N | VM_OC_PUT_BLOCK) \ + VM_OC_CALL | VM_OC_PUT_BLOCK) \ CBC_OPCODE (CBC_CALL0_PROP, CBC_NO_FLAG, -3, \ - VM_OC_CALL_PROP_N) \ + VM_OC_CALL) \ CBC_OPCODE (CBC_CALL0_PROP_PUSH_RESULT, CBC_NO_FLAG, -2, \ - VM_OC_CALL_PROP_N | VM_OC_PUT_STACK) \ + VM_OC_CALL | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_CALL0_PROP_BLOCK, CBC_NO_FLAG, -3, \ - VM_OC_CALL_PROP_N | VM_OC_PUT_BLOCK) \ + VM_OC_CALL | VM_OC_PUT_BLOCK) \ CBC_OPCODE (CBC_CALL1, CBC_NO_FLAG, -2, \ - VM_OC_CALL_N) \ + VM_OC_CALL) \ CBC_OPCODE (CBC_CALL1_PUSH_RESULT, CBC_NO_FLAG, -1, \ - VM_OC_CALL_N | VM_OC_PUT_STACK) \ + VM_OC_CALL | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_CALL1_BLOCK, CBC_NO_FLAG, -2, \ - VM_OC_CALL_N | VM_OC_PUT_BLOCK) \ + VM_OC_CALL | VM_OC_PUT_BLOCK) \ CBC_OPCODE (CBC_CALL1_PROP, CBC_NO_FLAG, -4, \ - VM_OC_CALL_PROP_N) \ + VM_OC_CALL) \ CBC_OPCODE (CBC_CALL1_PROP_PUSH_RESULT, CBC_NO_FLAG, -3, \ - VM_OC_CALL_PROP_N | VM_OC_PUT_STACK) \ + VM_OC_CALL | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_CALL1_PROP_BLOCK, CBC_NO_FLAG, -4, \ - VM_OC_CALL_PROP_N | VM_OC_PUT_BLOCK) \ + VM_OC_CALL | VM_OC_PUT_BLOCK) \ CBC_OPCODE (CBC_CALL2, CBC_NO_FLAG, -3, \ - VM_OC_CALL_N) \ + VM_OC_CALL) \ CBC_OPCODE (CBC_CALL2_PUSH_RESULT, CBC_NO_FLAG, -2, \ - VM_OC_CALL_N | VM_OC_PUT_STACK) \ + VM_OC_CALL | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_CALL2_BLOCK, CBC_NO_FLAG, -3, \ - VM_OC_CALL_N | VM_OC_PUT_BLOCK) \ + VM_OC_CALL | VM_OC_PUT_BLOCK) \ CBC_OPCODE (CBC_CALL2_PROP, CBC_NO_FLAG, -4, \ - VM_OC_CALL_PROP_N) \ + VM_OC_CALL) \ CBC_OPCODE (CBC_CALL2_PROP_PUSH_RESULT, CBC_NO_FLAG, -3, \ - VM_OC_CALL_PROP_N | VM_OC_PUT_STACK) \ + VM_OC_CALL | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_CALL2_PROP_BLOCK, CBC_NO_FLAG, -4, \ - VM_OC_CALL_PROP_N | VM_OC_PUT_BLOCK) \ + VM_OC_CALL | VM_OC_PUT_BLOCK) \ \ /* Binary assignment opcodes. */ \ CBC_OPCODE (CBC_ASSIGN, CBC_NO_FLAG, -3, \ diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index ae492b999c..d3432bde90 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -35,74 +35,6 @@ * @{ */ -/** - * 'Function call' opcode handler. - * - * See also: ECMA-262 v5, 11.2.3 - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -ecma_value_t -opfunc_call_n (ecma_value_t this_value, /**< this object value */ - ecma_value_t func_value, /**< function object value */ - const ecma_value_t *arguments_list_p, /**< stack pointer */ - ecma_length_t arguments_list_len) /**< number of arguments */ -{ - ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); - - if (!ecma_op_is_callable (func_value)) - { - return ecma_raise_type_error (""); - } - - ecma_object_t *func_obj_p = ecma_get_object_from_value (func_value); - - ret_value = ecma_op_function_call (func_obj_p, - this_value, - arguments_list_p, - arguments_list_len); - - return ret_value; -} /* opfunc_call_n */ - -/** - * 'Constructor call' opcode handler. - * - * See also: ECMA-262 v5, 11.2.2 - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -ecma_value_t -opfunc_construct_n (ecma_value_t constructor_value, /**< constructor object value */ - const ecma_value_t *arguments_list_p, /**< stack pointer */ - ecma_length_t arguments_list_len) /**< number of arguments */ -{ - ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); - - if (!ecma_is_constructor (constructor_value)) - { - ret_value = ecma_raise_type_error (""); - } - else - { - ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor_value); - - ECMA_TRY_CATCH (construction_ret_value, - ecma_op_function_construct (constructor_obj_p, - arguments_list_p, - arguments_list_len), - ret_value); - - ret_value = ecma_copy_value (construction_ret_value, true); - - ECMA_FINALIZE (construction_ret_value); - } - - return ret_value; -} /* opfunc_construct_n */ - /** * 'Variable declaration' opcode handler. * diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 5f1e9cce57..67de80c1db 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -56,14 +56,6 @@ typedef enum ecma_value_t vm_var_decl (vm_frame_ctx_t *, ecma_string_t *); -ecma_value_t -opfunc_call_n (ecma_value_t, ecma_value_t, - const ecma_value_t *, ecma_length_t); - -ecma_value_t -opfunc_construct_n (ecma_value_t, - const ecma_value_t *, ecma_length_t); - ecma_value_t opfunc_equal_value (ecma_value_t, ecma_value_t); diff --git a/jerry-core/vm/vm-defines.h b/jerry-core/vm/vm-defines.h index c607e5f58b..cfed962537 100644 --- a/jerry-core/vm/vm-defines.h +++ b/jerry-core/vm/vm-defines.h @@ -46,11 +46,14 @@ typedef struct uint8_t *byte_code_p; /**< current byte code pointer */ uint8_t *byte_code_start_p; /**< byte code start pointer */ ecma_value_t *registers_p; /**< register start pointer */ + ecma_value_t *stack_top_p; /**< stack top pointer */ lit_cpointer_t *literal_start_p; /**< literal list start pointer */ ecma_object_t *lex_env_p; /**< current lexical environment */ ecma_value_t this_binding; /**< this binding */ + ecma_value_t call_block_result; /**< preserve block result during a call */ uint16_t context_depth; /**< current context depth */ - bool is_eval_code; /**< eval mode flag */ + uint8_t is_eval_code; /**< eval mode flag */ + uint8_t call_operation; /**< perform a call or construct operation */ } vm_frame_ctx_t; /** diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 423a4ebd54..af909f647b 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -327,6 +327,128 @@ vm_get_implicit_this_value (ecma_value_t *this_value_p) /**< [in,out] this value return false; } /* vm_get_implicit_this_value */ +/** + * 'Function call' opcode handler. + * + * See also: ECMA-262 v5, 11.2.3 + */ +static void +opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ +{ + uint8_t opcode = frame_ctx_p->byte_code_p[0]; + uint32_t arguments_list_len; + + if (opcode >= CBC_CALL0) + { + arguments_list_len = (unsigned int) ((opcode - CBC_CALL0) / 6); + } + else + { + arguments_list_len = frame_ctx_p->byte_code_p[1]; + } + + bool is_call_prop = ((opcode - CBC_CALL) % 6) >= 3; + + ecma_value_t this_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len; + + if (is_call_prop) + { + this_value = stack_top_p[-3]; + + if (vm_get_implicit_this_value (&this_value)) + { + ecma_free_value (stack_top_p[-3]); + stack_top_p[-3] = this_value; + } + } + + ecma_value_t func_value = stack_top_p[-1]; + ecma_value_t completion_value; + + if (!ecma_op_is_callable (func_value)) + { + completion_value = ecma_raise_type_error (""); + } + else + { + ecma_object_t *func_obj_p = ecma_get_object_from_value (func_value); + + completion_value = ecma_op_function_call (func_obj_p, + this_value, + stack_top_p, + arguments_list_len); + } + + is_direct_eval_form_call = false; + + /* Free registers. */ + for (uint32_t i = 0; i < arguments_list_len; i++) + { + ecma_free_value (stack_top_p[i]); + } + + if (is_call_prop) + { + ecma_free_value (*(--stack_top_p)); + ecma_free_value (*(--stack_top_p)); + } + + ecma_free_value (stack_top_p[-1]); + stack_top_p[-1] = completion_value; + + frame_ctx_p->stack_top_p = stack_top_p; +} /* opfunc_call */ + +/** + * 'Constructor call' opcode handler. + * + * See also: ECMA-262 v5, 11.2.2 + */ +static void +opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ +{ + uint8_t opcode = frame_ctx_p->byte_code_p[0]; + unsigned int arguments_list_len; + + if (opcode >= CBC_NEW0) + { + arguments_list_len = (unsigned int) (opcode - CBC_NEW0); + } + else + { + arguments_list_len = frame_ctx_p->byte_code_p[1]; + } + + ecma_value_t *stack_top_p = frame_ctx_p->stack_top_p - arguments_list_len; + ecma_value_t constructor_value = stack_top_p[-1]; + ecma_value_t completion_value; + + if (!ecma_is_constructor (constructor_value)) + { + completion_value = ecma_raise_type_error (""); + } + else + { + ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor_value); + + completion_value = ecma_op_function_construct (constructor_obj_p, + stack_top_p, + arguments_list_len); + } + + /* Free registers. */ + for (uint32_t i = 0; i < arguments_list_len; i++) + { + ecma_free_value (stack_top_p[i]); + } + + ecma_free_value (stack_top_p[-1]); + stack_top_p[-1] = completion_value; + + frame_ctx_p->stack_top_p = stack_top_p; +} /* opfunc_construct */ + /** * Indicate which value should be freed. */ @@ -572,7 +694,7 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ * * @return ecma value */ -ecma_value_t +static ecma_value_t __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; @@ -621,7 +743,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ const_literal_end = args_p->const_literal_end; } - stack_top_p = frame_ctx_p->registers_p + register_end; + stack_top_p = frame_ctx_p->stack_top_p; /* Outer loop for exception handling. */ while (true) @@ -1216,50 +1338,22 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (*byte_code_p >= CBC_CALL && *byte_code_p <= CBC_CALL2_PROP_BLOCK); continue; } - case VM_OC_CALL_N: - case VM_OC_CALL_PROP_N: - { - right_value = (unsigned int) ((opcode - CBC_CALL0) / 6); - /* FALLTHRU */ - } case VM_OC_CALL: - case VM_OC_CALL_PROP: { - ecma_value_t this_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + JERRY_ASSERT (free_flags == 0); - stack_top_p -= right_value; - - if (VM_OC_GROUP_GET_INDEX (opcode_data) >= VM_OC_CALL_PROP_N) + if (frame_ctx_p->call_operation == VM_NO_EXEC_OP) { - this_value = stack_top_p[-3]; - - if (vm_get_implicit_this_value (&this_value)) - { - ecma_free_value (stack_top_p[-3]); - stack_top_p[-3] = this_value; - } + frame_ctx_p->call_operation = VM_EXEC_CALL; + frame_ctx_p->byte_code_p = byte_code_start_p; + frame_ctx_p->stack_top_p = stack_top_p; + frame_ctx_p->call_block_result = block_result; + return; } + frame_ctx_p->call_operation = VM_NO_EXEC_OP; - last_completion_value = opfunc_call_n (this_value, - stack_top_p[-1], - stack_top_p, - right_value); - - is_direct_eval_form_call = false; - - /* Free registers. */ - for (uint32_t i = 0; i < right_value; i++) - { - ecma_free_value (stack_top_p[i]); - } - - ecma_free_value (*(--stack_top_p)); - - if (VM_OC_GROUP_GET_INDEX (opcode_data) >= VM_OC_CALL_PROP_N) - { - ecma_free_value (*(--stack_top_p)); - ecma_free_value (*(--stack_top_p)); - } + last_completion_value = *(--stack_top_p); + block_result = frame_ctx_p->call_block_result; if (ecma_is_value_error (last_completion_value)) { @@ -1274,29 +1368,24 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { ecma_free_value (last_completion_value); } - break; } - case VM_OC_NEW_N: - { - right_value = opcode - (uint32_t) CBC_NEW0; - /* FALLTHRU */ - } case VM_OC_NEW: { - stack_top_p -= right_value; - - last_completion_value = opfunc_construct_n (stack_top_p[-1], - stack_top_p, - right_value); + JERRY_ASSERT (free_flags == 0); - /* Free registers. */ - for (uint32_t i = 0; i < right_value; i++) + if (frame_ctx_p->call_operation == VM_NO_EXEC_OP) { - ecma_free_value (stack_top_p[i]); + frame_ctx_p->call_operation = VM_EXEC_CONSTRUCT; + frame_ctx_p->byte_code_p = byte_code_start_p; + frame_ctx_p->stack_top_p = stack_top_p; + frame_ctx_p->call_block_result = block_result; + return; } + frame_ctx_p->call_operation = VM_NO_EXEC_OP; - ecma_free_value (*(--stack_top_p)); + last_completion_value = *(--stack_top_p); + block_result = frame_ctx_p->call_block_result; if (ecma_is_value_error (last_completion_value)) { @@ -2265,6 +2354,8 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ register_end = args_p->register_end; } + frame_ctx_p->stack_top_p = frame_ctx_p->registers_p + register_end; + if (arg_list_len == 0) { ecma_collection_header_t *arg_collection_p = (ecma_collection_header_t *) arg_p; @@ -2320,9 +2411,30 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ prev_context_p = vm_top_context_p; vm_top_context_p = frame_ctx_p; - vm_init_loop (frame_ctx_p); + completion_value = vm_init_loop (frame_ctx_p); - completion_value = vm_loop (frame_ctx_p); + if (!ecma_is_value_error (completion_value)) + { + while (true) + { + completion_value = vm_loop (frame_ctx_p); + + if (frame_ctx_p->call_operation == VM_NO_EXEC_OP) + { + break; + } + + if (frame_ctx_p->call_operation == VM_EXEC_CALL) + { + opfunc_call (frame_ctx_p); + } + else + { + JERRY_ASSERT (frame_ctx_p->call_operation == VM_EXEC_CONSTRUCT); + opfunc_construct (frame_ctx_p); + } + } + } /* Free arguments and registers */ for (uint32_t i = 0; i < register_end; i++) @@ -2418,6 +2530,7 @@ vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data heade frame_ctx.this_binding = this_binding_value; frame_ctx.context_depth = 0; frame_ctx.is_eval_code = is_eval_code; + frame_ctx.call_operation = VM_NO_EXEC_OP; arg_list_len++; diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index efa8826fea..e6718d5b25 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -107,14 +107,8 @@ typedef enum VM_OC_THROW, /**< throw */ VM_OC_THROW_REFERENCE_ERROR, /**< throw reference error */ - /* The PROP forms must get the highest opcodes. */ VM_OC_EVAL, /**< eval */ - VM_OC_CALL_N, /**< call n */ VM_OC_CALL, /**< call */ - VM_OC_CALL_PROP_N, /**< call property n */ - VM_OC_CALL_PROP, /**< call property */ - - VM_OC_NEW_N, /**< new n */ VM_OC_NEW, /**< new */ VM_OC_JUMP, /**< jump */ @@ -185,13 +179,24 @@ typedef enum VM_OC_PUT_BLOCK = VM_OC_PUT_DATA_CREATE_FLAG (0x8), } vm_oc_put_types; +/** + * Non-recursive vm_loop: the vm_loop can be suspended + * to execute a call /construct operation. These return + * types of the vm_loop tells whether a call operation + * is in progress or the vm_loop is finished. + */ +typedef enum +{ + VM_NO_EXEC_OP, /**< do nothing */ + VM_EXEC_CALL, /**< invoke a function */ + VM_EXEC_CONSTRUCT, /**< construct a new object */ +} vm_call_operation; + extern void vm_init (ecma_compiled_code_t *, bool); extern void vm_finalize (void); extern jerry_completion_code_t vm_run_global (void); extern ecma_value_t vm_run_eval (ecma_compiled_code_t *, bool); -extern ecma_value_t vm_loop (vm_frame_ctx_t *); - extern ecma_value_t vm_run (const ecma_compiled_code_t *, ecma_value_t, ecma_object_t *, bool, const ecma_value_t *, ecma_length_t);