Use custom dispatcher for Function.prototype routines (#2967)

Binary size gain:
     - Intel: ~70B (gcc-7.3)
     - Arm: 50 B (arm-linux-gnueabi-gcc-7.3)

Co-authored-by: Gabor Loki loki@inf.u-szeged.hu
JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
This commit is contained in:
Robert Fancsik
2019-07-17 14:10:05 +02:00
committed by Dániel Bátyai
parent c0b8845530
commit 7aa3bfdc6d
2 changed files with 204 additions and 191 deletions
@@ -29,6 +29,23 @@
#define ECMA_BUILTINS_INTERNAL #define ECMA_BUILTINS_INTERNAL
#include "ecma-builtins-internal.h" #include "ecma-builtins-internal.h"
/**
* This object has a custom dispatch function.
*/
#define BUILTIN_CUSTOM_DISPATCH
/**
* List of built-in routine identifiers.
*/
enum
{
ECMA_FUNCTION_PROTOTYPE_ROUTINE_START = ECMA_BUILTIN_ID__COUNT - 1,
ECMA_FUNCTION_PROTOTYPE_TO_STRING,
ECMA_FUNCTION_PROTOTYPE_CALL,
ECMA_FUNCTION_PROTOTYPE_APPLY,
ECMA_FUNCTION_PROTOTYPE_BIND,
};
#define BUILTIN_INC_HEADER_NAME "ecma-builtin-function-prototype.inc.h" #define BUILTIN_INC_HEADER_NAME "ecma-builtin-function-prototype.inc.h"
#define BUILTIN_UNDERSCORED_ID function_prototype #define BUILTIN_UNDERSCORED_ID function_prototype
#include "ecma-builtin-internal-routines-template.inc.h" #include "ecma-builtin-internal-routines-template.inc.h"
@@ -58,19 +75,9 @@
* Returned value must be freed with ecma_free_value. * Returned value must be freed with ecma_free_value.
*/ */
static ecma_value_t static ecma_value_t
ecma_builtin_function_prototype_object_to_string (ecma_value_t this_arg) /**< this argument */ ecma_builtin_function_prototype_object_to_string (void)
{ {
ecma_value_t ret_value = ECMA_VALUE_EMPTY; return ecma_make_magic_string_value (LIT_MAGIC_STRING__FUNCTION_TO_STRING);
if (!ecma_op_is_callable (this_arg))
{
ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a function."));
}
else
{
ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__FUNCTION_TO_STRING);
}
return ret_value;
} /* ecma_builtin_function_prototype_object_to_string */ } /* ecma_builtin_function_prototype_object_to_string */
/** /**
@@ -83,35 +90,22 @@ ecma_builtin_function_prototype_object_to_string (ecma_value_t this_arg) /**< th
* Returned value must be freed with ecma_free_value. * Returned value must be freed with ecma_free_value.
*/ */
static ecma_value_t static ecma_value_t
ecma_builtin_function_prototype_object_apply (ecma_value_t this_arg, /**< this argument */ ecma_builtin_function_prototype_object_apply (ecma_object_t *func_obj_p, /**< this argument object */
ecma_value_t arg1, /**< first argument */ ecma_value_t arg1, /**< first argument */
ecma_value_t arg2) /**< second argument */ ecma_value_t arg2) /**< second argument */
{ {
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
/* 1. */
if (!ecma_op_is_callable (this_arg))
{
ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a function."));
}
else
{
ecma_object_t *func_obj_p = ecma_get_object_from_value (this_arg);
/* 2. */ /* 2. */
if (ecma_is_value_null (arg2) || ecma_is_value_undefined (arg2)) if (ecma_is_value_null (arg2) || ecma_is_value_undefined (arg2))
{ {
ret_value = ecma_op_function_call (func_obj_p, arg1, NULL, 0); return ecma_op_function_call (func_obj_p, arg1, NULL, 0);
} }
else
{
/* 3. */ /* 3. */
if (!ecma_is_value_object (arg2)) if (!ecma_is_value_object (arg2))
{ {
ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object.")); return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object."));
} }
else
{
ecma_object_t *obj_p = ecma_get_object_from_value (arg2); ecma_object_t *obj_p = ecma_get_object_from_value (arg2);
/* 4. */ /* 4. */
@@ -137,11 +131,11 @@ ecma_builtin_function_prototype_object_apply (ecma_value_t this_arg, /**< this a
if (length >= ECMA_FUNCTION_APPLY_ARGUMENT_COUNT_LIMIT) if (length >= ECMA_FUNCTION_APPLY_ARGUMENT_COUNT_LIMIT)
{ {
ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("Too many arguments declared for Function.apply().")); return ecma_raise_range_error (ECMA_ERR_MSG ("Too many arguments declared for Function.apply()."));
} }
else
{
/* 6. */ /* 6. */
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
JMEM_DEFINE_LOCAL_ARRAY (arguments_list_p, length, ecma_value_t); JMEM_DEFINE_LOCAL_ARRAY (arguments_list_p, length, ecma_value_t);
uint32_t index = 0; uint32_t index = 0;
@@ -176,10 +170,6 @@ ecma_builtin_function_prototype_object_apply (ecma_value_t this_arg, /**< this a
} }
JMEM_FINALIZE_LOCAL_ARRAY (arguments_list_p); JMEM_FINALIZE_LOCAL_ARRAY (arguments_list_p);
}
}
}
}
return ret_value; return ret_value;
} /* ecma_builtin_function_prototype_object_apply */ } /* ecma_builtin_function_prototype_object_apply */
@@ -194,18 +184,10 @@ ecma_builtin_function_prototype_object_apply (ecma_value_t this_arg, /**< this a
* Returned value must be freed with ecma_free_value. * Returned value must be freed with ecma_free_value.
*/ */
static ecma_value_t static ecma_value_t
ecma_builtin_function_prototype_object_call (ecma_value_t this_arg, /**< this argument */ ecma_builtin_function_prototype_object_call (ecma_object_t *func_obj_p , /**< this argument object */
const ecma_value_t *arguments_list_p, /**< list of arguments */ const ecma_value_t *arguments_list_p, /**< list of arguments */
ecma_length_t arguments_number) /**< number of arguments */ ecma_length_t arguments_number) /**< number of arguments */
{ {
if (!ecma_op_is_callable (this_arg))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a function."));
}
else
{
ecma_object_t *func_obj_p = ecma_get_object_from_value (this_arg);
if (arguments_number == 0) if (arguments_number == 0)
{ {
/* Even a 'this' argument is missing. */ /* Even a 'this' argument is missing. */
@@ -214,14 +196,11 @@ ecma_builtin_function_prototype_object_call (ecma_value_t this_arg, /**< this ar
NULL, NULL,
0); 0);
} }
else
{
return ecma_op_function_call (func_obj_p, return ecma_op_function_call (func_obj_p,
arguments_list_p[0], arguments_list_p[0],
arguments_list_p + 1, arguments_list_p + 1,
(ecma_length_t) (arguments_number - 1u)); (ecma_length_t) (arguments_number - 1u));
}
}
} /* ecma_builtin_function_prototype_object_call */ } /* ecma_builtin_function_prototype_object_call */
/** /**
@@ -234,19 +213,10 @@ ecma_builtin_function_prototype_object_call (ecma_value_t this_arg, /**< this ar
* Returned value must be freed with ecma_free_value. * Returned value must be freed with ecma_free_value.
*/ */
static ecma_value_t static ecma_value_t
ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this argument */ ecma_builtin_function_prototype_object_bind (ecma_object_t *this_arg_obj_p , /**< this argument object */
const ecma_value_t *arguments_list_p, /**< list of arguments */ const ecma_value_t *arguments_list_p, /**< list of arguments */
ecma_length_t arguments_number) /**< number of arguments */ ecma_length_t arguments_number) /**< number of arguments */
{ {
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
/* 2. */
if (!ecma_op_is_callable (this_arg))
{
ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a function."));
}
else
{
/* 4. 11. 18. */ /* 4. 11. 18. */
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
@@ -262,7 +232,6 @@ ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this ar
/* 8. */ /* 8. */
ext_function_p = (ecma_extended_object_t *) function_p; ext_function_p = (ecma_extended_object_t *) function_p;
ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg);
ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function, ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function,
this_arg_obj_p); this_arg_obj_p);
@@ -285,7 +254,6 @@ ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this ar
/* 8. */ /* 8. */
ext_function_p = (ecma_extended_object_t *) function_p; ext_function_p = (ecma_extended_object_t *) function_p;
ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg);
ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function, ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function,
this_arg_obj_p); this_arg_obj_p);
@@ -310,10 +278,7 @@ ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this ar
*/ */
/* 22. */ /* 22. */
ret_value = ecma_make_object_value (function_p); return ecma_make_object_value (function_p);
}
return ret_value;
} /* ecma_builtin_function_prototype_object_bind */ } /* ecma_builtin_function_prototype_object_bind */
/** /**
@@ -344,6 +309,54 @@ ecma_builtin_function_prototype_dispatch_construct (const ecma_value_t *argument
return ecma_raise_type_error (ECMA_ERR_MSG ("'Function.prototype' is not a constructor.")); return ecma_raise_type_error (ECMA_ERR_MSG ("'Function.prototype' is not a constructor."));
} /* ecma_builtin_function_prototype_dispatch_construct */ } /* ecma_builtin_function_prototype_dispatch_construct */
/**
* Dispatcher of the built-in's routines
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
ecma_value_t
ecma_builtin_function_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< built-in wide routine
* identifier */
ecma_value_t this_arg, /**< 'this' argument value */
const ecma_value_t arguments_list_p[], /**< list of arguments
* passed to routine */
ecma_length_t arguments_number) /**< length of arguments' list */
{
if (!ecma_op_is_callable (this_arg))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a function."));
}
ecma_object_t *func_obj_p = ecma_get_object_from_value (this_arg);
switch (builtin_routine_id)
{
case ECMA_FUNCTION_PROTOTYPE_TO_STRING:
{
return ecma_builtin_function_prototype_object_to_string ();
}
case ECMA_FUNCTION_PROTOTYPE_APPLY:
{
return ecma_builtin_function_prototype_object_apply (func_obj_p,
arguments_list_p[0],
arguments_list_p[1]);
}
case ECMA_FUNCTION_PROTOTYPE_CALL:
{
return ecma_builtin_function_prototype_object_call (func_obj_p, arguments_list_p, arguments_number);
}
case ECMA_FUNCTION_PROTOTYPE_BIND:
{
return ecma_builtin_function_prototype_object_bind (func_obj_p, arguments_list_p, arguments_number);
}
default:
{
JERRY_UNREACHABLE ();
}
}
} /* ecma_builtin_function_prototype_dispatch_routine */
/** /**
* @} * @}
* @} * @}
@@ -37,9 +37,9 @@ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
/* Routine properties: /* Routine properties:
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ecma_builtin_function_prototype_object_to_string, 0, 0) ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ECMA_FUNCTION_PROTOTYPE_TO_STRING, 0, 0)
ROUTINE (LIT_MAGIC_STRING_APPLY, ecma_builtin_function_prototype_object_apply, 2, 2) ROUTINE (LIT_MAGIC_STRING_APPLY, ECMA_FUNCTION_PROTOTYPE_APPLY, 2, 2)
ROUTINE (LIT_MAGIC_STRING_CALL, ecma_builtin_function_prototype_object_call, NON_FIXED, 1) ROUTINE (LIT_MAGIC_STRING_CALL, ECMA_FUNCTION_PROTOTYPE_CALL, NON_FIXED, 1)
ROUTINE (LIT_MAGIC_STRING_BIND, ecma_builtin_function_prototype_object_bind, NON_FIXED, 1) ROUTINE (LIT_MAGIC_STRING_BIND, ECMA_FUNCTION_PROTOTYPE_BIND, NON_FIXED, 1)
#include "ecma-builtin-helpers-macro-undefs.inc.h" #include "ecma-builtin-helpers-macro-undefs.inc.h"