/** * [[Call]] implementation for Function objects, * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) * or 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION), * and for built-in Function objects * from section 15 (ECMA_OBJECT_TYPE_FUNCTION). * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ ecma_value_t this_arg_value, /**< 'this' argument's value */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< length of arguments list */ { JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p)); JERRY_ASSERT (ecma_op_is_callable (ecma_make_object_value (func_obj_p))); ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION) { if (unlikely (ecma_get_object_is_builtin (func_obj_p))) { ret_value = ecma_builtin_dispatch_call (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); } else { /* Entering Function Code (ECMA-262 v5, 10.4.3) */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_obj_p; ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_func_p->u.function.scope_cp); // 8. ecma_value_t this_binding; bool is_strict; bool is_no_lex_env; const ecma_compiled_code_t *bytecode_data_p; bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, ext_func_p->u.function.bytecode_cp); is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) ? true : false; is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false; // 1. if (is_strict) { this_binding = ecma_copy_value (this_arg_value); } else if (ecma_is_value_undefined (this_arg_value) || ecma_is_value_null (this_arg_value)) { // 2. this_binding = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL)); } else { // 3., 4. this_binding = ecma_op_to_object (this_arg_value); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (this_binding)); } // 5. ecma_object_t *local_env_p; if (is_no_lex_env) { local_env_p = scope_p; } else { local_env_p = ecma_create_decl_lex_env (scope_p); if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED) { ecma_op_create_arguments_object (func_obj_p, local_env_p, arguments_list_p, arguments_list_len, bytecode_data_p); } } ret_value = vm_run (bytecode_data_p, this_binding, local_env_p, false, arguments_list_p, arguments_list_len); if (!is_no_lex_env) { ecma_deref_object (local_env_p); } ecma_free_value (this_binding); } } else if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
/** * 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 */