diff --git a/jerry-core/parser/js/parser.cpp b/jerry-core/parser/js/parser.cpp index 08a6d1b38..0dfbb5906 100644 --- a/jerry-core/parser/js/parser.cpp +++ b/jerry-core/parser/js/parser.cpp @@ -495,6 +495,19 @@ parse_argument_list (varg_list_type vlt, operand obj, uint8_t *args_count, opera { call_flags = (opcode_call_flags_t) (call_flags | OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM); } + else + { + /* + * Note: + * If function is called through Identifier, then the obj should be an Identifier reference, + * not register variable. + * Otherwise, if function is called immediately, without reference (for example, through anonymous + * function expression), the obj should be a register variable. + * + * See also: + * vm_helper_call_get_call_flags_and_this_arg + */ + } dump_varg_header_for_rewrite (vlt, obj); diff --git a/jerry-core/vm/opcodes.cpp b/jerry-core/vm/opcodes.cpp index 54994d7d6..f8d0d497c 100644 --- a/jerry-core/vm/opcodes.cpp +++ b/jerry-core/vm/opcodes.cpp @@ -706,6 +706,9 @@ opfunc_func_expr_n (opcode_t opdata, /**< operation data */ */ static ecma_value_t vm_helper_call_get_call_flags_and_this_arg (int_data_t *int_data_p, /**< interpreter context */ + opcode_counter_t var_idx_lit_oc, /**< opcode counter, corresponding to + * instruction with function_var_idx */ + idx_t var_idx, /**< idx, used to retrieve the called function object */ opcode_call_flags_t *out_flags_p) /**< out: call flags */ { JERRY_ASSERT (out_flags_p != NULL); @@ -741,11 +744,54 @@ vm_helper_call_get_call_flags_and_this_arg (int_data_t *int_data_p, /**< interpr if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG) { + /* 6.a.i */ get_this_completion_value = get_variable_value (int_data_p, this_arg_var_idx, false); } else { - get_this_completion_value = ecma_op_implicit_this_value (int_data_p->lex_env_p); + /* + * Note: + * If function object is in a register variable, then base is not lexical environment + * + * See also: + * parse_argument_list + */ + if (!is_reg_variable (int_data_p, var_idx)) + { + /* + * FIXME [PERF]: + * The second search for base lexical environment can be removed or performed less frequently. + * + * For example, in one of the following ways: + * - parser could dump meta information about whether current lexical environment chain + * can contain object-bound lexical environment, created using 'with' statement + * (in the case, the search should be performed, otherwise - it is unnecessary, + * as base lexical environment would be either the Global lexical environment, + * or a declarative lexical environment); + * - get_variable_value and opfunc_prop_getter could save last resolved base + * into interpreter context (in the case, `have_this_arg` can be unnecesary, + * as base would always be accessible through interpreter context; on the other hand, + * some stack-like description of active nested call expressions should be provided). + * + */ + + /* 6.b.i */ + ecma_string_t var_name_string; + lit_cpointer_t lit_cp = serializer_get_literal_cp_by_uid (var_idx, int_data_p->opcodes_p, var_idx_lit_oc); + ecma_new_ecma_string_on_stack_from_lit_cp (&var_name_string, lit_cp); + + ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (int_data_p->lex_env_p, + &var_name_string); + get_this_completion_value = ecma_op_implicit_this_value (ref_base_lex_env_p); + JERRY_ASSERT (ref_base_lex_env_p != NULL); + + ecma_check_that_ecma_string_need_not_be_freed (&var_name_string); + } + else + { + /* 7. a */ + get_this_completion_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); + } } JERRY_ASSERT (ecma_is_completion_value_normal (get_this_completion_value)); @@ -774,20 +820,23 @@ opfunc_call_n (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { const idx_t lhs_var_idx = opdata.data.call_n.lhs; - const idx_t func_name_lit_idx = opdata.data.call_n.name_lit_idx; + const idx_t function_var_idx = opdata.data.call_n.function_var_idx; const idx_t args_number_idx = opdata.data.call_n.arg_list; const opcode_counter_t lit_oc = int_data->pos; ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); - ECMA_TRY_CATCH (func_value, get_variable_value (int_data, func_name_lit_idx, false), ret_value); + ECMA_TRY_CATCH (func_value, get_variable_value (int_data, function_var_idx, false), ret_value); int_data->pos++; JERRY_ASSERT (!int_data->is_call_in_direct_eval_form); opcode_call_flags_t call_flags; - ecma_value_t this_value = vm_helper_call_get_call_flags_and_this_arg (int_data, &call_flags); + ecma_value_t this_value = vm_helper_call_get_call_flags_and_this_arg (int_data, + lit_oc, + function_var_idx, + &call_flags); MEM_DEFINE_LOCAL_ARRAY (arg_values, args_number_idx, ecma_value_t); diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 5e5cdddfa..4b0dcb0c2 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -171,7 +171,7 @@ opcode_counter_t calc_opcode_counter_from_idx_idx (const idx_t oc_idx_1, const i opcode_counter_t read_meta_opcode_counter (opcode_meta_type expected_type, int_data_t *int_data); #define OP_CALLS_AND_ARGS(p, a) \ - p##_3 (a, call_n, lhs, name_lit_idx, arg_list) \ + p##_3 (a, call_n, lhs, function_var_idx, arg_list) \ p##_3 (a, native_call, lhs, name, arg_list) \ p##_3 (a, construct_n, lhs, name_lit_idx, arg_list) \ p##_2 (a, func_decl_n, name_lit_idx, arg_list) \ diff --git a/tests/jerry/function-args.js b/tests/jerry/function-args.js index 8bd72e453..bfb54d164 100644 --- a/tests/jerry/function-args.js +++ b/tests/jerry/function-args.js @@ -60,3 +60,13 @@ try { catch (e) { assert (e instanceof ReferenceError); } + +function f2 () +{ + return this; +} + +with ({}) +{ + assert (f2 () === this); +}