From ed4ff8e5bb3c66353e2f98370d7842b1265128fd Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Tue, 26 May 2015 18:14:01 +0300 Subject: [PATCH] Introducing a function object's flag indicating whether Arguments object should be instantiated upon call of the function. The Arguments object is supposed to be unnecessary if function's code: - doesn't reference 'arguments' identifier; - doesn't reference 'eval' identifier (so, it doesn't perform direct call to eval). JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- .../ecma/operations/ecma-function-object.cpp | 73 +++++++++++++++---- .../ecma/operations/ecma-function-object.h | 2 + jerry-core/vm/opcodes.cpp | 20 +++++ 3 files changed, 81 insertions(+), 14 deletions(-) diff --git a/jerry-core/ecma/operations/ecma-function-object.cpp b/jerry-core/ecma/operations/ecma-function-object.cpp index e217b4ba1..54647f185 100644 --- a/jerry-core/ecma/operations/ecma-function-object.cpp +++ b/jerry-core/ecma/operations/ecma-function-object.cpp @@ -37,48 +37,60 @@ */ /** - * Pack 'is_strict' flag and opcode index to value + * Pack 'is_strict', 'do_instantiate_arguments_object' flags and opcode index to value * that can be stored in an [[Code]] internal property. * * @return packed value */ static uint32_t ecma_pack_code_internal_property_value (bool is_strict, /**< is code strict? */ + bool do_instantiate_args_obj, /**< should an Arguments object be + * instantiated for the code */ opcode_counter_t opcode_idx) /**< index of first opcode */ { uint32_t value = opcode_idx; const uint32_t is_strict_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 1); + const uint32_t do_instantiate_arguments_object_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 2); JERRY_ASSERT (((value) & (1u << is_strict_bit_offset)) == 0); + JERRY_ASSERT (((value) & (1u << do_instantiate_arguments_object_bit_offset)) == 0); if (is_strict) { value |= (1u << is_strict_bit_offset); } + if (do_instantiate_args_obj) + { + value |= (1u << do_instantiate_arguments_object_bit_offset); + } + return value; } /* ecma_pack_code_internal_property_value */ /** - * Unpack 'is_strict' flag and opcode index from value + * Unpack 'is_strict', 'do_instantiate_arguments_object' flags and opcode index from value * that can be stored in an [[Code]] internal property. * * @return opcode index */ static opcode_counter_t ecma_unpack_code_internal_property_value (uint32_t value, /**< packed value */ - bool* out_is_strict_p) /**< out: is code strict? */ + bool* out_is_strict_p, /**< out: is code strict? */ + bool* out_do_instantiate_args_obj_p) /**< should an Arguments object be + * instantiated for the code */ { JERRY_ASSERT (out_is_strict_p != NULL); + JERRY_ASSERT (out_do_instantiate_args_obj_p != NULL); const uint32_t is_strict_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 1); + const uint32_t do_instantiate_arguments_object_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 2); - bool is_strict = ((value & (1u << is_strict_bit_offset)) != 0); - *out_is_strict_p = is_strict; + *out_is_strict_p = ((value & (1u << is_strict_bit_offset)) != 0); + *out_do_instantiate_args_obj_p = ((value & (1u << do_instantiate_arguments_object_bit_offset)) != 0); + value &= ~((1u << is_strict_bit_offset) | (1u << do_instantiate_arguments_object_bit_offset)); - opcode_counter_t opcode_idx = (opcode_counter_t) (value & ~(1u << is_strict_bit_offset)); - - return opcode_idx; + return (opcode_counter_t) value; } /* ecma_unpack_code_internal_property_value */ /** @@ -144,6 +156,8 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], /**< f ecma_length_t formal_parameters_number, /**< formal parameters list's length */ ecma_object_t *scope_p, /**< function's scope */ bool is_strict, /**< 'strict' flag */ + bool do_instantiate_arguments_object, /**< should an Arguments object be instantiated + * for the function object upon call */ opcode_counter_t first_opcode_idx) /**< index of first opcode of function's body */ { // 1., 4., 13. @@ -185,6 +199,7 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], /**< f // 12. ecma_property_t *code_prop_p = ecma_create_internal_property (f, ECMA_INTERNAL_PROPERTY_CODE); code_prop_p->u.internal_property.value = ecma_pack_code_internal_property_value (is_strict, + do_instantiate_arguments_object, first_opcode_idx); // 14. @@ -339,10 +354,11 @@ ecma_op_create_external_function_object (ecma_external_pointer_t code_p) /**< po } /* ecma_op_create_external_function_object */ /** - * Setup variables for arguments listed in formal parameter list. + * Setup variables for arguments listed in formal parameter list, + * and, if necessary, Arguments object with 'arguments' binding. * * See also: - * Declaration binding instantiation (ECMA-262 v5, 10.5), block 4 + * Declaration binding instantiation (ECMA-262 v5, 10.5), block 4 and 7 * * @return completion value * Returned value must be freed with ecma_free_completion_value @@ -352,7 +368,10 @@ ecma_function_call_setup_args_variables (ecma_object_t *func_obj_p, /**< Functio ecma_object_t *env_p, /**< lexical environment */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len, /**< length of argument list */ - bool is_strict) /**< flag indicating strict mode */ + bool is_strict, /**< flag indicating strict mode */ + bool do_instantiate_arguments_object) /**< flag indicating whether + * Arguments object should be + * instantiated */ { ecma_property_t *formal_parameters_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS); @@ -417,6 +436,24 @@ ecma_function_call_setup_args_variables (ecma_object_t *func_obj_p, /**< Functio } } + if (do_instantiate_arguments_object) + { + /* + * According to ECMA-262 v5, 10.5, the Arguments object should be instantiated + * after instantiating declared functions, and only if there is no binding named 'arguments' + * by that time. + * + * However, we can setup Arguments object and 'arguments' binding here, because: + * - instantiation of Arguments object itself doesn't have any side effects; + * - if 'arguments' is name of a declared function in current scope, + * value of the binding would be overwritten, execution would proceed in correct state. + * - declaration of function, named 'arguments', is considered to be unrecommended (and so, rare) case, + * so instantiation of Arguments object here, in general, is supposed to not affect resource consumption + * significantly. + */ + JERRY_UNIMPLEMENTED ("Instantiate Arguments object and setup 'arguments' implicit variable"); + } + return ecma_make_empty_completion_value (); } /* ecma_function_call_setup_args_variables */ @@ -543,8 +580,11 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ uint32_t code_prop_value = code_prop_p->u.internal_property.value; bool is_strict; + bool do_instantiate_args_obj; // 8. - opcode_counter_t code_first_opcode_idx = ecma_unpack_code_internal_property_value (code_prop_value, &is_strict); + opcode_counter_t code_first_opcode_idx = ecma_unpack_code_internal_property_value (code_prop_value, + &is_strict, + &do_instantiate_args_obj); ecma_value_t this_binding; // 1. @@ -576,7 +616,8 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ local_env_p, arguments_list_p, arguments_list_len, - is_strict), + is_strict, + do_instantiate_args_obj), ret_value); ecma_completion_value_t completion = vm_run_from_pos (code_first_opcode_idx, @@ -769,14 +810,18 @@ ecma_op_function_declaration (ecma_object_t *lex_env_p, /**< lexical environment ecma_string_t* formal_parameter_list_p[], /**< formal parameters list */ ecma_length_t formal_parameter_list_length, /**< length of formal parameters list */ bool is_strict, /**< flag indicating if function is declared in strict mode code */ + bool do_instantiate_arguments_object, /**< flag, indicating whether an Arguments object + * should be instantiated for the function object + * upon call */ bool is_configurable_bindings) /**< flag indicating whether function - is declared in eval code */ + * is declared in eval code */ { // b. ecma_object_t *func_obj_p = ecma_op_create_function_object (formal_parameter_list_p, formal_parameter_list_length, lex_env_p, is_strict, + do_instantiate_arguments_object, function_code_opcode_idx); // c. diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index 76e76065c..7e230ac1b 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -34,6 +34,7 @@ ecma_op_create_function_object (ecma_string_t* formal_parameter_list_p[], ecma_length_t formal_parameters_number, ecma_object_t *scope_p, bool is_strict, + bool do_instantiate_arguments_object, opcode_counter_t first_opcode_idx); extern ecma_object_t* ecma_op_create_external_function_object (ecma_external_pointer_t code_p); @@ -60,6 +61,7 @@ ecma_op_function_declaration (ecma_object_t *lex_env_p, ecma_string_t* formal_parameter_list_p[], ecma_length_t formal_parameter_list_length, bool is_strict, + bool do_instantiate_arguments_object, bool is_configurable_bindings); /** diff --git a/jerry-core/vm/opcodes.cpp b/jerry-core/vm/opcodes.cpp index 05bb69060..3b8446fd5 100644 --- a/jerry-core/vm/opcodes.cpp +++ b/jerry-core/vm/opcodes.cpp @@ -443,6 +443,7 @@ function_declaration (int_data_t *int_data, /**< interpreter context */ ecma_length_t args_number) /**< number of arguments */ { bool is_strict = int_data->is_strict; + bool do_instantiate_arguments_object = true; const bool is_configurable_bindings = int_data->is_eval_code; const opcode_counter_t function_code_end_oc = (opcode_counter_t) ( @@ -455,6 +456,14 @@ function_declaration (int_data_t *int_data, /**< interpreter context */ { is_strict = true; } + if ((scope_flags & OPCODE_SCOPE_CODE_FLAGS_NOT_REF_ARGUMENTS_IDENTIFIER) + && (scope_flags & OPCODE_SCOPE_CODE_FLAGS_NOT_REF_EVAL_IDENTIFIER)) + { + /* the code doesn't use 'arguments' identifier + * and doesn't perform direct call to eval, + * so Arguments object can't be referenced */ + do_instantiate_arguments_object = false; + } ecma_string_t *function_name_string_p = ecma_new_ecma_string_from_lit_index (function_name_lit_id); @@ -464,6 +473,7 @@ function_declaration (int_data_t *int_data, /**< interpreter context */ args_names, args_number, is_strict, + do_instantiate_arguments_object, is_configurable_bindings); ecma_deref_ecma_string (function_name_string_p); @@ -541,6 +551,7 @@ opfunc_func_expr_n (opcode_t opdata, /**< operation data */ fill_params_list (int_data, params_number, params_names); bool is_strict = int_data->is_strict; + bool do_instantiate_arguments_object = true; function_code_end_oc = (opcode_counter_t) (read_meta_opcode_counter (OPCODE_META_TYPE_FUNCTION_END, int_data) + int_data->pos); @@ -552,6 +563,14 @@ opfunc_func_expr_n (opcode_t opdata, /**< operation data */ { is_strict = true; } + if ((scope_flags & OPCODE_SCOPE_CODE_FLAGS_NOT_REF_ARGUMENTS_IDENTIFIER) + && (scope_flags & OPCODE_SCOPE_CODE_FLAGS_NOT_REF_EVAL_IDENTIFIER)) + { + /* the code doesn't use 'arguments' identifier + * and doesn't perform direct call to eval, + * so Arguments object can't be referenced */ + do_instantiate_arguments_object = false; + } ecma_object_t *scope_p; ecma_string_t *function_name_string_p = NULL; @@ -576,6 +595,7 @@ opfunc_func_expr_n (opcode_t opdata, /**< operation data */ params_number, scope_p, is_strict, + do_instantiate_arguments_object, int_data->pos); ret_value = set_variable_value (int_data, lit_oc,