Use custom dispatcher for Object.prototype routines (#2965)

Binary size gain:
     - Intel: ~250B (gcc-7.3)
     - Arm: ~65B (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:09:29 +02:00 committed by Dániel Bátyai
parent 603cd88006
commit f158dd4fb5
2 changed files with 157 additions and 105 deletions

View File

@ -30,6 +30,27 @@
#define ECMA_BUILTINS_INTERNAL
#include "ecma-builtins-internal.h"
/**
* This object has a custom dispatch function.
*/
#define BUILTIN_CUSTOM_DISPATCH
/**
* List of built-in routine identifiers.
*/
enum
{
/* Note: these 6 routines must be in this order */
ECMA_OBJECT_PROTOTYPE_ROUTINE_START = ECMA_BUILTIN_ID__COUNT - 1,
ECMA_OBJECT_PROTOTYPE_TO_STRING,
ECMA_OBJECT_PROTOTYPE_VALUE_OF,
ECMA_OBJECT_PROTOTYPE_TO_LOCALE_STRING,
ECMA_OBJECT_PROTOTYPE_IS_PROTOTYPE_OF,
ECMA_OBJECT_PROTOTYPE_HAS_OWN_PROPERTY,
ECMA_OBJECT_PROTOTYPE_PROPERTY_IS_ENUMERABLE,
};
#define BUILTIN_INC_HEADER_NAME "ecma-builtin-object-prototype.inc.h"
#define BUILTIN_UNDERSCORED_ID object_prototype
#include "ecma-builtin-internal-routines-template.inc.h"
@ -84,37 +105,30 @@ ecma_builtin_object_prototype_object_value_of (ecma_value_t this_arg) /**< this
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_object_prototype_object_to_locale_string (ecma_value_t this_arg) /**< this argument */
ecma_builtin_object_prototype_object_to_locale_string (ecma_object_t *obj_p) /**< this argument */
{
ecma_value_t return_value = ECMA_VALUE_EMPTY;
/* 1. */
ECMA_TRY_CATCH (obj_val,
ecma_op_to_object (this_arg),
return_value);
ecma_object_t *obj_p = ecma_get_object_from_value (obj_val);
/* 2. */
ECMA_TRY_CATCH (to_string_val,
ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_TO_STRING_UL),
return_value);
ecma_value_t to_string_val = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_TO_STRING_UL);
if (ECMA_IS_VALUE_ERROR (to_string_val))
{
return to_string_val;
}
/* 3. */
if (!ecma_op_is_callable (to_string_val))
{
return_value = ecma_raise_type_error (ECMA_ERR_MSG ("'toString is missing or not a function.'"));
}
else
{
/* 4. */
ecma_object_t *to_string_func_obj_p = ecma_get_object_from_value (to_string_val);
return_value = ecma_op_function_call (to_string_func_obj_p, this_arg, NULL, 0);
ecma_free_value (to_string_val);
return ecma_raise_type_error (ECMA_ERR_MSG ("'toString is missing or not a function.'"));
}
ECMA_FINALIZE (to_string_val);
ECMA_FINALIZE (obj_val);
/* 4. */
ecma_object_t *to_string_func_obj_p = ecma_get_object_from_value (to_string_val);
ecma_value_t ret_value = ecma_op_function_call (to_string_func_obj_p, ecma_make_object_value (obj_p), NULL, 0);
return return_value;
ecma_deref_object (to_string_func_obj_p);
return ret_value;
} /* ecma_builtin_object_prototype_object_to_locale_string */
/**
@ -127,33 +141,10 @@ ecma_builtin_object_prototype_object_to_locale_string (ecma_value_t this_arg) /*
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_object_prototype_object_has_own_property (ecma_value_t this_arg, /**< this argument */
ecma_value_t arg) /**< first argument */
ecma_builtin_object_prototype_object_has_own_property (ecma_object_t *obj_p, /**< this argument */
ecma_string_t *prop_name_p) /**< first argument */
{
ecma_value_t return_value = ECMA_VALUE_EMPTY;
/* 1. */
ECMA_TRY_CATCH (to_string_val,
ecma_op_to_string (arg),
return_value);
/* 2. */
ECMA_TRY_CATCH (obj_val,
ecma_op_to_object (this_arg),
return_value);
ecma_string_t *property_name_string_p = ecma_get_string_from_value (to_string_val);
ecma_object_t *obj_p = ecma_get_object_from_value (obj_val);
/* 3. */
return_value = ecma_make_boolean_value (ecma_op_object_has_own_property (obj_p, property_name_string_p));
ECMA_FINALIZE (obj_val);
ECMA_FINALIZE (to_string_val);
return return_value;
return ecma_make_boolean_value (ecma_op_object_has_own_property (obj_p, prop_name_p));
} /* ecma_builtin_object_prototype_object_has_own_property */
/**
@ -166,38 +157,24 @@ ecma_builtin_object_prototype_object_has_own_property (ecma_value_t this_arg, /*
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_object_prototype_object_is_prototype_of (ecma_value_t this_arg, /**< this argument */
ecma_builtin_object_prototype_object_is_prototype_of (ecma_object_t *obj_p, /**< this argument */
ecma_value_t arg) /**< routine's first argument */
{
/* 1. Is the argument an object? */
if (!ecma_is_value_object (arg))
{
return ECMA_VALUE_FALSE;
}
ecma_value_t return_value = ECMA_VALUE_EMPTY;
/* 2. ToObject(this) */
ECMA_TRY_CATCH (obj_value,
ecma_op_to_object (this_arg),
return_value);
ecma_object_t *obj_p = ecma_get_object_from_value (obj_value);
/* 3. Compare prototype to object */
ECMA_TRY_CATCH (v_obj_value,
ecma_op_to_object (arg),
return_value);
ecma_value_t v_obj_value = ecma_op_to_object (arg);
if (ECMA_IS_VALUE_ERROR (v_obj_value))
{
return v_obj_value;
}
ecma_object_t *v_obj_p = ecma_get_object_from_value (v_obj_value);
bool is_prototype_of = ecma_op_object_is_prototype_of (obj_p, v_obj_p);
return_value = ecma_make_boolean_value (is_prototype_of);
ECMA_FINALIZE (v_obj_value);
ecma_value_t ret_value = ecma_make_boolean_value (ecma_op_object_is_prototype_of (obj_p, v_obj_p));
ECMA_FINALIZE (obj_value);
ecma_deref_object (v_obj_p);
return return_value;
return ret_value;
} /* ecma_builtin_object_prototype_object_is_prototype_of */
/**
@ -210,49 +187,124 @@ ecma_builtin_object_prototype_object_is_prototype_of (ecma_value_t this_arg, /**
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_object_prototype_object_property_is_enumerable (ecma_value_t this_arg, /**< this argument */
ecma_value_t arg) /**< routine's first argument */
ecma_builtin_object_prototype_object_property_is_enumerable (ecma_object_t *obj_p, /**< this argument */
ecma_string_t *prop_name_p) /**< first argument */
{
ecma_value_t return_value = ECMA_VALUE_EMPTY;
/* 1. */
ECMA_TRY_CATCH (to_string_val,
ecma_op_to_string (arg),
return_value);
/* 2. */
ECMA_TRY_CATCH (obj_val,
ecma_op_to_object (this_arg),
return_value);
ecma_string_t *property_name_string_p = ecma_get_string_from_value (to_string_val);
ecma_object_t *obj_p = ecma_get_object_from_value (obj_val);
/* 3. */
ecma_property_t property = ecma_op_object_get_own_property (obj_p,
property_name_string_p,
prop_name_p,
NULL,
ECMA_PROPERTY_GET_NO_OPTIONS);
/* 4. */
if (property != ECMA_PROPERTY_TYPE_NOT_FOUND && property != ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP)
{
bool is_enumerable = ecma_is_property_enumerable (property);
return ecma_make_boolean_value (ecma_is_property_enumerable (property));
}
return_value = ecma_make_boolean_value (is_enumerable);
return ECMA_VALUE_FALSE;
} /* ecma_builtin_object_prototype_object_property_is_enumerable */
/**
* Dispatcher of the built-in's routines
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
ecma_value_t
ecma_builtin_object_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 */
{
JERRY_UNUSED (arguments_number);
/* no specialization */
if (builtin_routine_id <= ECMA_OBJECT_PROTOTYPE_VALUE_OF)
{
if (builtin_routine_id == ECMA_OBJECT_PROTOTYPE_TO_STRING)
{
return ecma_builtin_object_prototype_object_to_string (this_arg);
}
JERRY_ASSERT (builtin_routine_id <= ECMA_OBJECT_PROTOTYPE_VALUE_OF);
return ecma_builtin_object_prototype_object_value_of (this_arg);
}
if (builtin_routine_id <= ECMA_OBJECT_PROTOTYPE_IS_PROTOTYPE_OF)
{
if (builtin_routine_id == ECMA_OBJECT_PROTOTYPE_IS_PROTOTYPE_OF)
{
/* 15.2.4.6.1. */
if (!ecma_is_value_object (arguments_list_p[0]))
{
return ECMA_VALUE_FALSE;
}
}
ecma_value_t to_object = ecma_op_to_object (this_arg);
if (ECMA_IS_VALUE_ERROR (to_object))
{
return to_object;
}
ecma_object_t *obj_p = ecma_get_object_from_value (to_object);
ecma_value_t ret_value;
if (builtin_routine_id == ECMA_OBJECT_PROTOTYPE_IS_PROTOTYPE_OF)
{
ret_value = ecma_builtin_object_prototype_object_is_prototype_of (obj_p, arguments_list_p[0]);
}
else
{
ret_value = ecma_builtin_object_prototype_object_to_locale_string (obj_p);
}
ecma_deref_object (obj_p);
return ret_value;
}
JERRY_ASSERT (builtin_routine_id >= ECMA_OBJECT_PROTOTYPE_HAS_OWN_PROPERTY);
ecma_string_t *prop_name_p = ecma_op_to_prop_name (arguments_list_p[0]);
if (prop_name_p == NULL)
{
return ECMA_VALUE_ERROR;
}
ecma_value_t to_object = ecma_op_to_object (this_arg);
if (ECMA_IS_VALUE_ERROR (to_object))
{
ecma_deref_ecma_string (prop_name_p);
return to_object;
}
ecma_object_t *obj_p = ecma_get_object_from_value (to_object);
ecma_value_t ret_value;
if (builtin_routine_id == ECMA_OBJECT_PROTOTYPE_HAS_OWN_PROPERTY)
{
ret_value = ecma_builtin_object_prototype_object_has_own_property (obj_p, prop_name_p);
}
else
{
return_value = ECMA_VALUE_FALSE;
ret_value = ecma_builtin_object_prototype_object_property_is_enumerable (obj_p, prop_name_p);
}
ECMA_FINALIZE (obj_val);
ecma_deref_ecma_string (prop_name_p);
ecma_deref_object (obj_p);
ECMA_FINALIZE (to_string_val);
return return_value;
} /* ecma_builtin_object_prototype_object_property_is_enumerable */
return ret_value;
} /* ecma_builtin_object_prototype_dispatch_routine */
/**
* @}

View File

@ -29,11 +29,11 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
/* Routine properties:
* (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_object_prototype_object_to_string, 0, 0)
ROUTINE (LIT_MAGIC_STRING_VALUE_OF_UL, ecma_builtin_object_prototype_object_value_of, 0, 0)
ROUTINE (LIT_MAGIC_STRING_TO_LOCALE_STRING_UL, ecma_builtin_object_prototype_object_to_locale_string, 0, 0)
ROUTINE (LIT_MAGIC_STRING_HAS_OWN_PROPERTY_UL, ecma_builtin_object_prototype_object_has_own_property, 1, 1)
ROUTINE (LIT_MAGIC_STRING_IS_PROTOTYPE_OF_UL, ecma_builtin_object_prototype_object_is_prototype_of, 1, 1)
ROUTINE (LIT_MAGIC_STRING_PROPERTY_IS_ENUMERABLE_UL, ecma_builtin_object_prototype_object_property_is_enumerable, 1, 1)
ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ECMA_OBJECT_PROTOTYPE_TO_STRING, 0, 0)
ROUTINE (LIT_MAGIC_STRING_VALUE_OF_UL, ECMA_OBJECT_PROTOTYPE_VALUE_OF, 0, 0)
ROUTINE (LIT_MAGIC_STRING_TO_LOCALE_STRING_UL, ECMA_OBJECT_PROTOTYPE_TO_LOCALE_STRING, 0, 0)
ROUTINE (LIT_MAGIC_STRING_HAS_OWN_PROPERTY_UL, ECMA_OBJECT_PROTOTYPE_HAS_OWN_PROPERTY, 1, 1)
ROUTINE (LIT_MAGIC_STRING_IS_PROTOTYPE_OF_UL, ECMA_OBJECT_PROTOTYPE_IS_PROTOTYPE_OF, 1, 1)
ROUTINE (LIT_MAGIC_STRING_PROPERTY_IS_ENUMERABLE_UL, ECMA_OBJECT_PROTOTYPE_PROPERTY_IS_ENUMERABLE, 1, 1)
#include "ecma-builtin-helpers-macro-undefs.inc.h"