Parse functions directly (#2015)

This patch adds direct function source code parsing, which
is useful to avoid source code duplications. The patch
also improves the Function constructor.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2017-09-21 11:03:23 +02:00
committed by Dániel Bátyai
parent 7713d30702
commit 8d916a44f1
11 changed files with 427 additions and 244 deletions
@@ -65,116 +65,53 @@ ecma_builtin_function_dispatch_call (const ecma_value_t *arguments_list_p, /**<
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_function_helper_get_function_expression (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
ecma_builtin_function_helper_get_function_arguments (const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< number of arguments */
{
JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);
ecma_string_t *left_parenthesis_str_p, *right_parenthesis_str_p;
ecma_string_t *left_brace_str_p, *right_brace_str_p;
ecma_string_t *comma_str_p;
ecma_string_t *function_kw_str_p, *empty_str_p;
ecma_string_t *expr_str_p, *concated_str_p;
left_parenthesis_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_LEFT_PARENTHESIS_CHAR);
right_parenthesis_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_RIGHT_PARENTHESIS_CHAR);
left_brace_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_LEFT_BRACE_CHAR);
right_brace_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR);
comma_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_COMMA_CHAR);
function_kw_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_FUNCTION);
empty_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING__EMPTY);
/* First, we only process the function arguments skipping the function body */
ecma_length_t number_of_function_args = (arguments_list_len == 0 ? 0 : arguments_list_len - 1);
expr_str_p = ecma_concat_ecma_strings (left_parenthesis_str_p, function_kw_str_p);
concated_str_p = ecma_concat_ecma_strings (expr_str_p, left_parenthesis_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
for (ecma_length_t idx = 0;
idx < number_of_function_args && ecma_is_value_empty (ret_value);
idx++)
if (arguments_list_len <= 1)
{
ECMA_TRY_CATCH (str_arg_value,
ecma_op_to_string (arguments_list_p[idx]),
ret_value);
ecma_string_t *str_p = ecma_get_string_from_value (str_arg_value);
concated_str_p = ecma_concat_ecma_strings (expr_str_p, str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
if (idx < number_of_function_args - 1)
{
concated_str_p = ecma_concat_ecma_strings (expr_str_p, comma_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
}
ECMA_FINALIZE (str_arg_value);
return ecma_make_string_value (ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY));
}
if (ecma_is_value_empty (ret_value))
ecma_value_t final_str = ecma_op_to_string (arguments_list_p[0]);
if (arguments_list_len == 2 || ECMA_IS_VALUE_ERROR (final_str))
{
concated_str_p = ecma_concat_ecma_strings (expr_str_p, right_parenthesis_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
concated_str_p = ecma_concat_ecma_strings (expr_str_p, left_brace_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
if (arguments_list_len != 0)
{
ECMA_TRY_CATCH (str_arg_value,
ecma_op_to_string (arguments_list_p[arguments_list_len - 1]),
ret_value);
ecma_string_t *body_str_p = ecma_get_string_from_value (str_arg_value);
concated_str_p = ecma_concat_ecma_strings (expr_str_p, body_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
ECMA_FINALIZE (str_arg_value);
}
concated_str_p = ecma_concat_ecma_strings (expr_str_p, right_brace_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
concated_str_p = ecma_concat_ecma_strings (expr_str_p, right_parenthesis_str_p);
ecma_deref_ecma_string (expr_str_p);
expr_str_p = concated_str_p;
return final_str;
}
ecma_string_t *comma_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_COMMA_CHAR);
for (ecma_length_t idx = 1; idx < arguments_list_len - 1; idx++)
{
ecma_value_t new_str = ecma_op_to_string (arguments_list_p[idx]);
if (ECMA_IS_VALUE_ERROR (new_str))
{
ecma_free_value (final_str);
/* Return with the error. */
final_str = new_str;
break;
}
ecma_string_t *final_str_p = ecma_get_string_from_value (final_str);
ecma_string_t *fragment_str_p = ecma_concat_ecma_strings (final_str_p, comma_str_p);
ecma_deref_ecma_string (final_str_p);
ecma_string_t *new_str_p = ecma_get_string_from_value (new_str);
final_str_p = ecma_concat_ecma_strings (fragment_str_p, new_str_p);
ecma_deref_ecma_string (new_str_p);
ecma_deref_ecma_string (fragment_str_p);
final_str = ecma_make_string_value (final_str_p);
}
ecma_deref_ecma_string (left_parenthesis_str_p);
ecma_deref_ecma_string (right_parenthesis_str_p);
ecma_deref_ecma_string (left_brace_str_p);
ecma_deref_ecma_string (right_brace_str_p);
ecma_deref_ecma_string (comma_str_p);
ecma_deref_ecma_string (function_kw_str_p);
ecma_deref_ecma_string (empty_str_p);
if (ecma_is_value_empty (ret_value))
{
ret_value = ecma_make_string_value (expr_str_p);
}
else
{
ecma_deref_ecma_string (expr_str_p);
}
return ret_value;
} /* ecma_builtin_function_helper_get_function_expression */
return final_str;
} /* ecma_builtin_function_helper_get_function_arguments */
/**
* Handle calling [[Construct]] of built-in Function object
@@ -190,18 +127,63 @@ ecma_builtin_function_dispatch_construct (const ecma_value_t *arguments_list_p,
{
JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);
ecma_value_t arguments_value = ecma_builtin_function_helper_get_function_arguments (arguments_list_p,
arguments_list_len);
ECMA_TRY_CATCH (arguments_value,
ecma_builtin_function_helper_get_function_expression (arguments_list_p,
arguments_list_len),
ret_value);
if (ECMA_IS_VALUE_ERROR (arguments_value))
{
return arguments_value;
}
ecma_string_t *function_expression_p = ecma_get_string_from_value (arguments_value);
ecma_value_t function_body_value;
ret_value = ecma_op_eval (function_expression_p, false, false);
if (arguments_list_len > 0)
{
function_body_value = ecma_op_to_string (arguments_list_p[arguments_list_len - 1]);
ECMA_FINALIZE (arguments_value);
if (ECMA_IS_VALUE_ERROR (function_body_value))
{
ecma_free_value (arguments_value);
return function_body_value;
}
}
else
{
/* Very unlikely code path, not optimized. */
function_body_value = ecma_make_string_value (ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY));
}
ecma_string_t *arguments_str_p = ecma_get_string_from_value (arguments_value);
ecma_string_t *function_body_str_p = ecma_get_string_from_value (function_body_value);
ECMA_STRING_TO_UTF8_STRING (arguments_str_p, arguments_buffer_p, arguments_buffer_size);
ECMA_STRING_TO_UTF8_STRING (function_body_str_p, function_body_buffer_p, function_body_buffer_size);
ecma_compiled_code_t *bytecode_data_p;
ecma_value_t ret_value = parser_parse_script (arguments_buffer_p,
arguments_buffer_size,
function_body_buffer_p,
function_body_buffer_size,
false,
&bytecode_data_p);
if (!ECMA_IS_VALUE_ERROR (ret_value))
{
JERRY_ASSERT (ecma_is_value_true (ret_value));
ecma_object_t *func_obj_p = ecma_op_create_function_object (ecma_get_global_environment (),
bytecode_data_p);
ecma_bytecode_deref (bytecode_data_p);
ret_value = ecma_make_object_value (func_obj_p);
}
ECMA_FINALIZE_UTF8_STRING (function_body_buffer_p, function_body_buffer_size);
ECMA_FINALIZE_UTF8_STRING (arguments_buffer_p, arguments_buffer_size);
ecma_deref_ecma_string (arguments_str_p);
ecma_deref_ecma_string (function_body_str_p);
return ret_value;
} /* ecma_builtin_function_dispatch_construct */