Rework function.bind (#1406)

The new code does not use value collections which reduces the argument array size by half.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2016-10-25 13:15:14 +02:00 committed by Dániel Bátyai
parent dc1e26933f
commit 945fbef110
6 changed files with 126 additions and 191 deletions

View File

@ -29,6 +29,9 @@ JERRY_STATIC_ASSERT (((sizeof (ecma_property_value_t) - 1) & sizeof (ecma_proper
JERRY_STATIC_ASSERT (sizeof (ecma_string_t) == sizeof (uint64_t),
size_of_ecma_string_t_must_be_less_than_or_equal_to_8_bytes);
JERRY_STATIC_ASSERT (sizeof (ecma_extended_object_t) - sizeof (ecma_object_t) <= sizeof (uint64_t),
size_of_ecma_extended_object_part_must_be_less_than_or_equal_to_8_bytes);
/** \addtogroup ecma ECMA
* @{
*

View File

@ -199,8 +199,6 @@ ecma_gc_mark_property (ecma_property_t *property_p) /**< property */
}
case ECMA_PROPERTY_TYPE_INTERNAL:
{
uint32_t property_value = ECMA_PROPERTY_VALUE_PTR (property_p)->value;
switch (ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (property_p))
{
case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */
@ -210,52 +208,7 @@ ecma_gc_mark_property (ecma_property_t *property_p) /**< property */
break;
}
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: /* an ecma value */
{
if (ecma_is_value_object (property_value))
{
ecma_object_t *obj_p = ecma_get_object_from_value (property_value);
ecma_gc_set_object_visited (obj_p, true);
}
break;
}
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS: /* a collection of ecma values */
{
ecma_collection_header_t *bound_arg_list_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_header_t,
property_value);
ecma_collection_iterator_t bound_args_iterator;
ecma_collection_iterator_init (&bound_args_iterator, bound_arg_list_p);
for (ecma_length_t i = 0; i < bound_arg_list_p->unit_number; i++)
{
bool is_moved = ecma_collection_iterator_next (&bound_args_iterator);
JERRY_ASSERT (is_moved);
if (ecma_is_value_object (*bound_args_iterator.current_value_p))
{
ecma_object_t *obj_p = ecma_get_object_from_value (*bound_args_iterator.current_value_p);
ecma_gc_set_object_visited (obj_p, true);
}
}
break;
}
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION: /* an object */
{
ecma_object_t *obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, property_value);
ecma_gc_set_object_visited (obj_p, true);
break;
}
case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type,
* but number of the real internal property types */
default:
{
JERRY_UNREACHABLE ();
break;
@ -306,24 +259,52 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
ecma_gc_set_object_visited (proto_p, true);
}
if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARGUMENTS)
switch (ecma_get_object_type (object_p))
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
case ECMA_OBJECT_TYPE_ARGUMENTS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_object_p->u.arguments.lex_env_cp);
ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_object_p->u.arguments.lex_env_cp);
ecma_gc_set_object_visited (lex_env_p, true);
}
else if (!ecma_get_object_is_builtin (object_p)
&& ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION)
{
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
ecma_gc_set_object_visited (lex_env_p, true);
break;
}
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) object_p;
ecma_length_t args_length = ext_function_p->u.bound_function.args_length;
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_func_p->u.function.scope_cp);
JERRY_ASSERT (args_length > 0);
ecma_gc_set_object_visited (scope_p, true);
for (ecma_length_t i = 0; i < args_length; i++)
{
if (ecma_is_value_object (args_p[i]))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (args_p[i]), true);
}
}
break;
}
case ECMA_OBJECT_TYPE_FUNCTION:
{
if (!ecma_get_object_is_builtin (object_p))
{
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_func_p->u.function.scope_cp);
ecma_gc_set_object_visited (scope_p, true);
}
break;
}
default:
{
break;
}
}
}
@ -538,6 +519,22 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */
ecma_dealloc_extended_object (ext_object_p, sizeof (ecma_extended_object_t) + formal_params_size);
return;
}
if (object_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
{
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) object_p;
ecma_length_t args_length = ext_function_p->u.bound_function.args_length;
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
for (ecma_length_t i = 0; i < args_length; i++)
{
ecma_free_value_if_not_object (args_p[i]);
}
size_t args_size = args_length * sizeof (ecma_value_t);
ecma_dealloc_extended_object (ext_function_p, sizeof (ecma_extended_object_t) + args_size);
return;
}
}
ecma_dealloc_object (object_p);

View File

@ -199,12 +199,6 @@ typedef enum
{
ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE, /**< native handle associated with an object */
ECMA_INTERNAL_PROPERTY_FREE_CALLBACK, /**< object's native free callback */
/** Bound function internal properties **/
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS,
ECMA_INTERNAL_PROPERTY_INSTANTIATED_MASK_32_63, /**< Bit-mask of non-instantiated
* built-in's properties (bits 32-63) */
@ -612,6 +606,15 @@ typedef struct
uint32_t length; /**< length of names */
} arguments;
/*
* Description of bound function object.
*/
struct
{
ecma_value_t target_function; /**< target function */
ecma_length_t args_length; /**< length of arguments */
} bound_function;
ecma_external_pointer_t external_function; /**< external function */
} u;
} ecma_extended_object_t;

View File

@ -771,8 +771,6 @@ ecma_free_internal_property (ecma_property_t *property_p) /**< the property */
{
JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL);
uint32_t property_value = ECMA_PROPERTY_VALUE_PTR (property_p)->value;
switch (ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (property_p))
{
case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */
@ -784,30 +782,11 @@ ecma_free_internal_property (ecma_property_t *property_p) /**< the property */
}
case ECMA_INTERNAL_PROPERTY_INSTANTIATED_MASK_32_63: /* an integer (bit-mask) */
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION:
{
break;
}
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS:
{
ecma_free_value_if_not_object (property_value);
break;
}
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS:
{
if (property_value != ECMA_NULL_POINTER)
{
ecma_free_values_collection (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_header_t, property_value),
false);
}
break;
}
case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type,
* but number of the real internal property types */
default:
{
JERRY_UNREACHABLE ();
break;

View File

@ -237,42 +237,42 @@ ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this ar
{
/* 4. 11. 18. */
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
ecma_length_t args_length = (arguments_number >= 1) ? arguments_number : 1;
size_t obj_size = sizeof (ecma_extended_object_t) + (args_length * sizeof (ecma_value_t));
ecma_object_t *function_p = ecma_create_object (prototype_obj_p,
0,
obj_size,
ECMA_OBJECT_TYPE_BOUND_FUNCTION);
ecma_deref_object (prototype_obj_p);
/* 7. */
ecma_value_t *target_function_prop_p;
target_function_prop_p = ecma_create_internal_property (function_p,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION);
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) function_p;
/* 7. */
ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg);
ECMA_SET_INTERNAL_VALUE_POINTER (*target_function_prop_p, this_arg_obj_p);
ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function,
this_arg_obj_p);
/* 8. */
ecma_value_t *bound_this_prop_p;
bound_this_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS);
const ecma_length_t arg_count = arguments_number;
ext_function_p->u.bound_function.args_length = args_length;
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
if (arg_count > 0)
*args_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
if (arguments_number > 0)
{
*bound_this_prop_p = ecma_copy_value_if_not_object (arguments_list_p[0]);
}
else
{
*bound_this_prop_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
*args_p = ecma_copy_value_if_not_object (arguments_list_p[0]);
}
if (arg_count > 1)
if (arguments_number > 1)
{
ecma_collection_header_t *bound_args_collection_p;
bound_args_collection_p = ecma_new_values_collection (&arguments_list_p[1], arg_count - 1, false);
ecma_value_t *bound_args_prop_p;
bound_args_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS);
ECMA_SET_INTERNAL_VALUE_POINTER (*bound_args_prop_p, bound_args_collection_p);
for (ecma_length_t i = 1; i < arguments_number; i++)
{
++args_p;
*args_p = ecma_copy_value_if_not_object (arguments_list_p[i]);
}
}
/*
@ -292,10 +292,8 @@ ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this ar
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (get_len_value));
JERRY_ASSERT (ecma_is_value_number (get_len_value));
const ecma_length_t bound_arg_count = arg_count > 1 ? arg_count - 1 : 0;
/* 15.a */
length = ecma_get_number_from_value (get_len_value) - ((ecma_number_t) bound_arg_count);
length = ecma_get_number_from_value (get_len_value) - ((ecma_number_t) (args_length - 1));
ecma_free_value (get_len_value);
/* 15.b */

View File

@ -93,44 +93,6 @@ ecma_is_constructor (ecma_value_t value) /**< ecma value */
|| ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
} /* ecma_is_constructor */
/**
* Helper function to merge argument lists
*
* See also:
* ECMA-262 v5, 15.3.4.5.1 step 4
* ECMA-262 v5, 15.3.4.5.2 step 4
*
* Used by:
* - [[Call]] implementation for Function objects.
* - [[Construct]] implementation for Function objects.
*/
static void
ecma_function_bind_merge_arg_lists (ecma_value_t *merged_args_list_p, /**< destination argument list */
ecma_collection_header_t *bound_arg_list_p, /**< bound argument list */
const ecma_value_t *arguments_list_p, /**< source arguments list */
ecma_length_t arguments_list_len) /**< length of source arguments list */
{
/* Performance optimization: only the values are copied. This is
* enough, since the original references keep these objects alive. */
ecma_collection_iterator_t bound_args_iterator;
ecma_collection_iterator_init (&bound_args_iterator, bound_arg_list_p);
for (ecma_length_t i = bound_arg_list_p->unit_number; i > 0; i--)
{
bool is_moved = ecma_collection_iterator_next (&bound_args_iterator);
JERRY_ASSERT (is_moved);
*merged_args_list_p++ = *bound_args_iterator.current_value_p;
}
while (arguments_list_len > 0)
{
*merged_args_list_p++ = *arguments_list_p++;
arguments_list_len--;
}
} /* ecma_function_bind_merge_arg_lists */
/**
* Function object creation operation.
*
@ -467,11 +429,11 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object *
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
/* 1. */
ecma_value_t *target_function_prop_p;
target_function_prop_p = ecma_get_internal_property (func_obj_p,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION);
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
ecma_object_t *target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, *target_function_prop_p);
ecma_object_t *target_func_obj_p;
target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_function_p->u.bound_function.target_function);
/* 3. */
ret_value = ecma_op_object_has_instance (target_func_obj_p, value);
@ -600,33 +562,29 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
JERRY_CONTEXT (is_direct_eval_form_call) = false;
/* 2-3. */
ecma_value_t *target_function_prop_p;
target_function_prop_p = ecma_get_internal_property (func_obj_p,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION);
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
ecma_object_t *target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, *target_function_prop_p);
ecma_object_t *target_func_obj_p;
target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_function_p->u.bound_function.target_function);
/* 4. */
ecma_value_t *bound_args_prop_p = ecma_find_internal_property (func_obj_p,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS);
ecma_value_t bound_this_value = *ecma_get_internal_property (func_obj_p,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS);
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
if (bound_args_prop_p != NULL)
ecma_value_t bound_this_value = *args_p;
ecma_length_t args_length = ext_function_p->u.bound_function.args_length;
JERRY_ASSERT (args_length > 0);
if (args_length > 1)
{
ecma_collection_header_t *bound_arg_list_p;
bound_arg_list_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_header_t, *bound_args_prop_p);
JERRY_ASSERT (bound_arg_list_p->unit_number > 0);
ecma_length_t merged_args_list_len = bound_arg_list_p->unit_number + arguments_list_len;
args_length--;
ecma_length_t merged_args_list_len = args_length + arguments_list_len;
JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t);
ecma_function_bind_merge_arg_lists (merged_args_list_p,
bound_arg_list_p,
arguments_list_p,
arguments_list_len);
memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t));
memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t));
/* 5. */
ret_value = ecma_op_function_call (target_func_obj_p,
@ -783,11 +741,11 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
/* 1. */
ecma_value_t *target_function_prop_p;
target_function_prop_p = ecma_get_internal_property (func_obj_p,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION);
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
ecma_object_t *target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, *target_function_prop_p);
ecma_object_t *target_func_obj_p;
target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_function_p->u.bound_function.target_function);
/* 2. */
if (!ecma_is_constructor (ecma_make_object_value (target_func_obj_p)))
@ -797,24 +755,21 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
else
{
/* 4. */
ecma_value_t *bound_args_prop_p;
bound_args_prop_p = ecma_find_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS);
ecma_length_t args_length = ext_function_p->u.bound_function.args_length;
if (bound_args_prop_p != NULL)
JERRY_ASSERT (args_length > 0);
if (args_length > 1)
{
ecma_collection_header_t *bound_arg_list_p;
bound_arg_list_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_header_t, *bound_args_prop_p);
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
JERRY_ASSERT (bound_arg_list_p->unit_number > 0);
ecma_length_t merged_args_list_len = bound_arg_list_p->unit_number + arguments_list_len;
args_length--;
ecma_length_t merged_args_list_len = args_length + arguments_list_len;
JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t);
ecma_function_bind_merge_arg_lists (merged_args_list_p,
bound_arg_list_p,
arguments_list_p,
arguments_list_len);
memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t));
memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t));
/* 5. */
ret_value = ecma_op_function_construct (target_func_obj_p,