Fix initialization of 'this' argument in 'call_n' opcode handler.

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
This commit is contained in:
Ruben Ayrapetyan 2015-07-11 01:20:06 +03:00 committed by Evgeny Gavrin
parent c84d31ce9e
commit aa415c670e
4 changed files with 77 additions and 5 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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) \

View File

@ -60,3 +60,13 @@ try {
catch (e) {
assert (e instanceof ReferenceError);
}
function f2 ()
{
return this;
}
with ({})
{
assert (f2 () === this);
}