/** * Arguments object creation operation. * * See also: ECMA-262 v5, 10.6 */ void ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function */ ecma_object_t *lex_env_p, /**< lexical environment the Arguments object is created for */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_number, /**< length of arguments list */ const ecma_compiled_code_t *bytecode_data_p) /**< byte code */ { // 2., 3., 6. ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); ecma_object_t *obj_p = ecma_create_object (prototype_p, false, true, ECMA_OBJECT_TYPE_GENERAL); ecma_deref_object (prototype_p); // 11.a, 11.b for (ecma_length_t indx = 0; indx < arguments_number; indx++) { ecma_value_t completion; ecma_string_t *indx_string_p = ecma_new_ecma_string_from_uint32 (indx); completion = ecma_builtin_helper_def_prop (obj_p, indx_string_p, arguments_list_p[indx], true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ false); /* Failure handling */ JERRY_ASSERT (ecma_is_value_true (completion)); ecma_deref_ecma_string (indx_string_p); } bool is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0; // 1. // 4. ecma_property_t *class_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CLASS); ECMA_PROPERTY_VALUE_PTR (class_prop_p)->value = LIT_MAGIC_STRING_ARGUMENTS_UL; // 7. ecma_string_t *length_magic_string_p = ecma_new_ecma_length_string (); ecma_value_t completion = ecma_builtin_helper_def_prop (obj_p, length_magic_string_p, ecma_make_uint32_value (arguments_number), true, /* Writable */ false, /* Enumerable */ true, /* Configurable */ false); /* Failure handling */ JERRY_ASSERT (ecma_is_value_true (completion)); ecma_deref_ecma_string (length_magic_string_p); ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); if (bytecode_data_p != NULL) { ecma_length_t formal_params_number; jmem_cpointer_t *literal_p; if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_data_p; uint8_t *byte_p = (uint8_t *) bytecode_data_p; formal_params_number = args_p->argument_end; literal_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint16_arguments_t)); } else { cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_data_p; uint8_t *byte_p = (uint8_t *) bytecode_data_p; formal_params_number = args_p->argument_end; literal_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint8_arguments_t)); } if (!is_strict && arguments_number > 0 && formal_params_number > 0) { // 8. ecma_object_t *map_p = ecma_op_create_object_object_noarg (); // 11.c for (uint32_t indx = 0; indx < formal_params_number; indx++) { // i. if (literal_p[indx] == JMEM_CP_NULL) { continue; } ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, literal_p[indx]); ecma_string_t *indx_string_p = ecma_new_ecma_string_from_uint32 ((uint32_t) indx); prop_desc.is_value_defined = true; prop_desc.value = ecma_make_string_value (name_p); prop_desc.is_configurable_defined = true; prop_desc.is_configurable = true; completion = ecma_op_object_define_own_property (map_p, indx_string_p, &prop_desc, false); JERRY_ASSERT (ecma_is_value_true (completion)); ecma_deref_ecma_string (indx_string_p); } // 12. ecma_set_object_type (obj_p, ECMA_OBJECT_TYPE_ARGUMENTS); /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_ARGUMENTS type. * * See also: ecma_object_get_class_name */ ecma_delete_property (obj_p, class_prop_p); ecma_property_t *parameters_map_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP); ECMA_SET_INTERNAL_VALUE_POINTER (ECMA_PROPERTY_VALUE_PTR (parameters_map_prop_p)->value, map_p); ecma_property_t *scope_prop_p = ecma_create_internal_property (map_p, ECMA_INTERNAL_PROPERTY_SCOPE); ECMA_SET_INTERNAL_VALUE_POINTER (ECMA_PROPERTY_VALUE_PTR (scope_prop_p)->value, lex_env_p); ecma_deref_object (map_p); } } // 13. if (!is_strict) { ecma_string_t *callee_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE); completion = ecma_builtin_helper_def_prop (obj_p, callee_magic_string_p, ecma_make_object_value (func_obj_p), true, /* Writable */ false, /* Enumerable */ true, /* Configurable */ false); /* Failure handling */ JERRY_ASSERT (ecma_is_value_true (completion)); ecma_deref_ecma_string (callee_magic_string_p); } else { ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER); // 14. prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_get_defined = true; prop_desc.get_p = thrower_p; prop_desc.is_set_defined = true; prop_desc.set_p = thrower_p; prop_desc.is_enumerable_defined = true; prop_desc.is_enumerable = false; prop_desc.is_configurable_defined = true; prop_desc.is_configurable = false; } ecma_string_t *callee_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE); completion = ecma_op_object_define_own_property (obj_p, callee_magic_string_p, &prop_desc, false); JERRY_ASSERT (ecma_is_value_true (completion)); ecma_deref_ecma_string (callee_magic_string_p); ecma_string_t *caller_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER); completion = ecma_op_object_define_own_property (obj_p, caller_magic_string_p, &prop_desc, false); JERRY_ASSERT (ecma_is_value_true (completion)); ecma_deref_ecma_string (caller_magic_string_p); ecma_deref_object (thrower_p); } ecma_string_t *arguments_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); if (is_strict) { ecma_op_create_immutable_binding (lex_env_p, arguments_string_p); ecma_op_initialize_immutable_binding (lex_env_p, arguments_string_p, ecma_make_object_value (obj_p)); } else { ecma_value_t completion = ecma_op_create_mutable_binding (lex_env_p, arguments_string_p, false); JERRY_ASSERT (ecma_is_value_empty (completion)); completion = ecma_op_set_mutable_binding (lex_env_p, arguments_string_p, ecma_make_object_value (obj_p), false); JERRY_ASSERT (ecma_is_value_empty (completion)); } ecma_deref_ecma_string (arguments_string_p); ecma_deref_object (obj_p); } /* ecma_op_create_arguments_object */
/** * 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 and 7 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ static ecma_completion_value_t ecma_function_call_setup_args_variables (ecma_object_t *func_obj_p, /**< Function object */ 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 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); ecma_collection_header_t *formal_parameters_p; formal_parameters_p = ECMA_GET_POINTER (ecma_collection_header_t, formal_parameters_prop_p->u.internal_property.value); if (formal_parameters_p != NULL) { ecma_length_t formal_parameters_count = formal_parameters_p->unit_number; ecma_collection_iterator_t formal_params_iterator; ecma_collection_iterator_init (&formal_params_iterator, formal_parameters_p); /* * Formal parameter list is stored in reversed order * * Although, specification defines ascending order of formal parameters list enumeration, * implementation enumerates the parameters in descending order. * * In the case, redundant SetMutableBinding invocation could be avoided. */ for (ssize_t n = (ssize_t) formal_parameters_count - 1; n >= 0; n--) { ecma_value_t v; if (n >= (ssize_t) arguments_list_len) { v = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } else { v = arguments_list_p[n]; } bool is_moved = ecma_collection_iterator_next (&formal_params_iterator); JERRY_ASSERT (is_moved); ecma_value_t formal_parameter_name_value = *formal_params_iterator.current_value_p; ecma_string_t *formal_parameter_name_string_p = ecma_get_string_from_value (formal_parameter_name_value); bool arg_already_declared = ecma_op_has_binding (env_p, formal_parameter_name_string_p); if (!arg_already_declared) { ecma_completion_value_t completion = ecma_op_create_mutable_binding (env_p, formal_parameter_name_string_p, false); if (ecma_is_completion_value_throw (completion)) { return completion; } JERRY_ASSERT (ecma_is_completion_value_empty (completion)); completion = ecma_op_set_mutable_binding (env_p, formal_parameter_name_string_p, v, is_strict); if (ecma_is_completion_value_throw (completion)) { return completion; } JERRY_ASSERT (ecma_is_completion_value_empty (completion)); } } } 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. */ ecma_string_t *arguments_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); bool binding_already_declared = ecma_op_has_binding (env_p, arguments_string_p); if (!binding_already_declared) { ecma_object_t *args_obj_p = ecma_op_create_arguments_object (func_obj_p, env_p, formal_parameters_p, arguments_list_p, arguments_list_len, is_strict); if (is_strict) { ecma_op_create_immutable_binding (env_p, arguments_string_p); ecma_op_initialize_immutable_binding (env_p, arguments_string_p, ecma_make_object_value (args_obj_p)); } else { ecma_completion_value_t completion = ecma_op_create_mutable_binding (env_p, arguments_string_p, false); JERRY_ASSERT (ecma_is_completion_value_empty (completion)); completion = ecma_op_set_mutable_binding (env_p, arguments_string_p, ecma_make_object_value (args_obj_p), false); JERRY_ASSERT (ecma_is_completion_value_empty (completion)); } ecma_deref_object (args_obj_p); } ecma_deref_ecma_string (arguments_string_p); } return ecma_make_empty_completion_value (); } /* ecma_function_call_setup_args_variables */