Fix get_variable_value invocation in opfunc_call_n; enhancement of exception handling in opfunc_obj_decl.

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
This commit is contained in:
Ruben Ayrapetyan 2015-06-28 16:49:25 +03:00 committed by Evgeny Gavrin
parent 06dffdec8f
commit 1dc7ed64d6

View File

@ -39,6 +39,10 @@
* The operator should return from the opcode handler with it's 'return value'.
*
* 5. No other operations with opcode handler's 'return value' variable should be performed.
*
* Note:
* get_variable_value, taking an idx should be called with instruction counter value,
* corresponding to the instruction, containing the idx argument.
*/
#define OP_UNIMPLEMENTED_LIST(op) \
@ -690,6 +694,72 @@ opfunc_func_expr_n (opcode_t opdata, /**< operation data */
return ret_value;
} /* opfunc_func_expr_n */
/**
* Get 'this' argument value and call flags mask for function call
*
* See also:
* ECMA-262 v5, 11.2.3, steps 6-7
* @return ecma-value
* Returned value must be freed with ecma_free_value
*/
static ecma_value_t
vm_helper_call_get_call_flags_and_this_arg (int_data_t *int_data_p, /**< interpreter context */
opcode_call_flags_t *out_flags_p) /**< out: call flags */
{
JERRY_ASSERT (out_flags_p != NULL);
bool is_increase_instruction_pointer;
opcode_call_flags_t call_flags = OPCODE_CALL_FLAGS__EMPTY;
idx_t this_arg_var_idx = INVALID_VALUE;
opcode_t next_opcode = vm_get_opcode (int_data_p->opcodes_p, int_data_p->pos);
if (next_opcode.op_idx == __op__idx_meta
&& next_opcode.data.meta.type == OPCODE_META_TYPE_CALL_SITE_INFO)
{
call_flags = (opcode_call_flags_t) next_opcode.data.meta.data_1;
if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
{
this_arg_var_idx = next_opcode.data.meta.data_2;
JERRY_ASSERT (is_reg_variable (int_data_p, this_arg_var_idx));
JERRY_ASSERT ((call_flags & OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM) == 0);
}
is_increase_instruction_pointer = true;
}
else
{
is_increase_instruction_pointer = false;
}
ecma_completion_value_t get_this_completion_value;
ecma_value_t this_value;
if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
{
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);
}
JERRY_ASSERT (ecma_is_completion_value_normal (get_this_completion_value));
this_value = ecma_get_completion_value_value (get_this_completion_value);
if (is_increase_instruction_pointer)
{
int_data_p->pos++;
}
*out_flags_p = call_flags;
return this_value;
} /* vm_helper_call_get_call_flags_and_this_arg */
/**
* 'Function call' opcode handler.
*
@ -713,28 +783,10 @@ opfunc_call_n (opcode_t opdata, /**< operation data */
int_data->pos++;
idx_t this_arg_var_idx = INVALID_VALUE;
opcode_call_flags_t call_flags = OPCODE_CALL_FLAGS__EMPTY;
JERRY_ASSERT (!int_data->is_call_in_direct_eval_form);
opcode_t next_opcode = vm_get_opcode (int_data->opcodes_p, int_data->pos);
if (next_opcode.op_idx == __op__idx_meta
&& next_opcode.data.meta.type == OPCODE_META_TYPE_CALL_SITE_INFO)
{
call_flags = (opcode_call_flags_t) next_opcode.data.meta.data_1;
if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
{
this_arg_var_idx = next_opcode.data.meta.data_2;
JERRY_ASSERT (is_reg_variable (int_data, this_arg_var_idx));
JERRY_ASSERT ((call_flags & OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM) == 0);
}
int_data->pos++;
}
opcode_call_flags_t call_flags;
ecma_value_t this_value = vm_helper_call_get_call_flags_and_this_arg (int_data, &call_flags);
MEM_DEFINE_LOCAL_ARRAY (arg_values, args_number_idx, ecma_value_t);
@ -748,20 +800,6 @@ opfunc_call_n (opcode_t opdata, /**< operation data */
{
JERRY_ASSERT (args_read == args_number_idx);
ecma_completion_value_t get_this_completion_value;
if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
{
get_this_completion_value = get_variable_value (int_data, this_arg_var_idx, false);
}
else
{
get_this_completion_value = ecma_op_implicit_this_value (int_data->lex_env_p);
}
JERRY_ASSERT (ecma_is_completion_value_normal (get_this_completion_value));
ecma_value_t this_value = ecma_get_completion_value_value (get_this_completion_value);
if (!ecma_op_is_callable (func_value))
{
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
@ -798,8 +836,6 @@ opfunc_call_n (opcode_t opdata, /**< operation data */
JERRY_ASSERT (!int_data->is_call_in_direct_eval_form);
}
}
ecma_free_completion_value (get_this_completion_value);
}
else
{
@ -817,6 +853,8 @@ opfunc_call_n (opcode_t opdata, /**< operation data */
MEM_FINALIZE_LOCAL_ARRAY (arg_values);
ecma_free_value (this_value, true);
ECMA_FINALIZE (func_value);
return ret_value;
@ -982,11 +1020,10 @@ opfunc_obj_decl (opcode_t opdata, /**< operation data */
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ecma_completion_value_t completion = ecma_make_empty_completion_value ();
ecma_object_t *obj_p = ecma_op_create_object_object_noarg ();
for (uint32_t prop_index = 0;
prop_index < args_number;
prop_index < args_number && ecma_is_completion_value_empty (ret_value);
prop_index++)
{
ecma_completion_value_t evaluate_prop_completion = vm_loop (int_data, NULL);
@ -1002,128 +1039,116 @@ opfunc_obj_decl (opcode_t opdata, /**< operation data */
|| type == OPCODE_META_TYPE_VARG_PROP_SETTER);
const idx_t prop_name_var_idx = next_opcode.data.meta.data_1;
JERRY_ASSERT (is_reg_variable (int_data, prop_name_var_idx));
const idx_t value_for_prop_desc_var_idx = next_opcode.data.meta.data_2;
ecma_completion_value_t value_for_prop_desc = get_variable_value (int_data,
value_for_prop_desc_var_idx,
false);
ECMA_TRY_CATCH (value_for_prop_desc,
get_variable_value (int_data,
value_for_prop_desc_var_idx,
false),
ret_value);
ECMA_TRY_CATCH (prop_name_value,
get_variable_value (int_data,
prop_name_var_idx,
false),
ret_value);
ECMA_TRY_CATCH (prop_name_str_value,
ecma_op_to_string (prop_name_value),
ret_value);
if (ecma_is_completion_value_normal (value_for_prop_desc))
bool is_throw_syntax_error = false;
ecma_string_t *prop_name_string_p = ecma_get_string_from_value (prop_name_str_value);
ecma_property_t *previous_p = ecma_op_object_get_own_property (obj_p, prop_name_string_p);
const bool is_previous_undefined = (previous_p == NULL);
const bool is_previous_data_desc = (!is_previous_undefined
&& previous_p->type == ECMA_PROPERTY_NAMEDDATA);
const bool is_previous_accessor_desc = (!is_previous_undefined
&& previous_p->type == ECMA_PROPERTY_NAMEDACCESSOR);
JERRY_ASSERT (is_previous_undefined || is_previous_data_desc || is_previous_accessor_desc);
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
{
JERRY_ASSERT (is_reg_variable (int_data, prop_name_var_idx));
prop_desc.is_enumerable_defined = true;
prop_desc.is_enumerable = true;
ECMA_TRY_CATCH (prop_name_value,
get_variable_value (int_data,
prop_name_var_idx,
false),
ret_value);
ECMA_TRY_CATCH (prop_name_str_value,
ecma_op_to_string (prop_name_value),
ret_value);
prop_desc.is_configurable_defined = true;
prop_desc.is_configurable = true;
}
bool is_throw_syntax_error = false;
if (type == OPCODE_META_TYPE_VARG_PROP_DATA)
{
prop_desc.is_value_defined = true;
prop_desc.value = value_for_prop_desc;
ecma_string_t *prop_name_string_p = ecma_get_string_from_value (prop_name_str_value);
ecma_property_t *previous_p = ecma_op_object_get_own_property (obj_p, prop_name_string_p);
prop_desc.is_writable_defined = true;
prop_desc.is_writable = true;
const bool is_previous_undefined = (previous_p == NULL);
const bool is_previous_data_desc = (!is_previous_undefined
&& previous_p->type == ECMA_PROPERTY_NAMEDDATA);
const bool is_previous_accessor_desc = (!is_previous_undefined
&& previous_p->type == ECMA_PROPERTY_NAMEDACCESSOR);
JERRY_ASSERT (is_previous_undefined || is_previous_data_desc || is_previous_accessor_desc);
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
if (!is_previous_undefined
&& ((is_previous_data_desc
&& int_data->is_strict)
|| is_previous_accessor_desc))
{
prop_desc.is_enumerable_defined = true;
prop_desc.is_enumerable = true;
prop_desc.is_configurable_defined = true;
prop_desc.is_configurable = true;
is_throw_syntax_error = true;
}
}
else if (type == OPCODE_META_TYPE_VARG_PROP_GETTER)
{
prop_desc.is_get_defined = true;
prop_desc.get_p = ecma_get_object_from_value (value_for_prop_desc);
if (type == OPCODE_META_TYPE_VARG_PROP_DATA)
if (!is_previous_undefined
&& is_previous_data_desc)
{
prop_desc.is_value_defined = true;
prop_desc.value = ecma_get_completion_value_value (value_for_prop_desc);
prop_desc.is_writable_defined = true;
prop_desc.is_writable = true;
if (!is_previous_undefined
&& ((is_previous_data_desc
&& int_data->is_strict)
|| is_previous_accessor_desc))
{
is_throw_syntax_error = true;
}
is_throw_syntax_error = true;
}
else if (type == OPCODE_META_TYPE_VARG_PROP_GETTER)
{
prop_desc.is_get_defined = true;
prop_desc.get_p = ecma_get_object_from_completion_value (value_for_prop_desc);
if (!is_previous_undefined
&& is_previous_data_desc)
{
is_throw_syntax_error = true;
}
}
else
{
prop_desc.is_set_defined = true;
prop_desc.set_p = ecma_get_object_from_completion_value (value_for_prop_desc);
if (!is_previous_undefined
&& is_previous_data_desc)
{
is_throw_syntax_error = true;
}
}
/* The SyntaxError should be treated as an early error */
JERRY_ASSERT (!is_throw_syntax_error);
ecma_completion_value_t define_prop_completion = ecma_op_object_define_own_property (obj_p,
prop_name_string_p,
&prop_desc,
false);
JERRY_ASSERT (ecma_is_completion_value_normal_true (define_prop_completion)
|| ecma_is_completion_value_normal_false (define_prop_completion));
ecma_free_completion_value (value_for_prop_desc);
ECMA_FINALIZE (prop_name_str_value);
ECMA_FINALIZE (prop_name_value);
}
else
{
completion = value_for_prop_desc;
prop_desc.is_set_defined = true;
prop_desc.set_p = ecma_get_object_from_value (value_for_prop_desc);
break;
if (!is_previous_undefined
&& is_previous_data_desc)
{
is_throw_syntax_error = true;
}
}
/* The SyntaxError should be treated as an early error */
JERRY_ASSERT (!is_throw_syntax_error);
ecma_completion_value_t define_prop_completion = ecma_op_object_define_own_property (obj_p,
prop_name_string_p,
&prop_desc,
false);
JERRY_ASSERT (ecma_is_completion_value_normal_true (define_prop_completion)
|| ecma_is_completion_value_normal_false (define_prop_completion));
ECMA_FINALIZE (prop_name_str_value);
ECMA_FINALIZE (prop_name_value);
ECMA_FINALIZE (value_for_prop_desc);
int_data->pos++;
}
else
{
JERRY_ASSERT (ecma_is_completion_value_throw (evaluate_prop_completion));
completion = evaluate_prop_completion;
break;
ret_value = evaluate_prop_completion;
}
}
if (ecma_is_completion_value_empty (completion))
if (ecma_is_completion_value_empty (ret_value))
{
ret_value = set_variable_value (int_data, obj_lit_oc, lhs_var_idx, ecma_make_object_value (obj_p));
}
else
{
JERRY_ASSERT (ecma_is_completion_value_throw (completion));
ret_value = completion;
JERRY_ASSERT (ecma_is_completion_value_throw (ret_value));
}
ecma_deref_object (obj_p);