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
+3
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), JERRY_STATIC_ASSERT (sizeof (ecma_string_t) == sizeof (uint64_t),
size_of_ecma_string_t_must_be_less_than_or_equal_to_8_bytes); 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 /** \addtogroup ecma ECMA
* @{ * @{
* *
+58 -61
View File
@@ -199,8 +199,6 @@ ecma_gc_mark_property (ecma_property_t *property_p) /**< property */
} }
case ECMA_PROPERTY_TYPE_INTERNAL: 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)) switch (ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (property_p))
{ {
case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */
@@ -210,52 +208,7 @@ ecma_gc_mark_property (ecma_property_t *property_p) /**< property */
break; break;
} }
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: /* an ecma value */ default:
{
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 */
{ {
JERRY_UNREACHABLE (); JERRY_UNREACHABLE ();
break; 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); 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, ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_object_p->u.arguments.lex_env_cp); ext_object_p->u.arguments.lex_env_cp);
ecma_gc_set_object_visited (lex_env_p, true); ecma_gc_set_object_visited (lex_env_p, true);
} break;
else if (!ecma_get_object_is_builtin (object_p) }
&& ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{ {
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; 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, JERRY_ASSERT (args_length > 0);
ext_func_p->u.function.scope_cp);
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); ecma_dealloc_extended_object (ext_object_p, sizeof (ecma_extended_object_t) + formal_params_size);
return; 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); ecma_dealloc_object (object_p);
+9 -6
View File
@@ -199,12 +199,6 @@ typedef enum
{ {
ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE, /**< native handle associated with an object */ ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE, /**< native handle associated with an object */
ECMA_INTERNAL_PROPERTY_FREE_CALLBACK, /**< object's native free callback */ 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 ECMA_INTERNAL_PROPERTY_INSTANTIATED_MASK_32_63, /**< Bit-mask of non-instantiated
* built-in's properties (bits 32-63) */ * built-in's properties (bits 32-63) */
@@ -612,6 +606,15 @@ typedef struct
uint32_t length; /**< length of names */ uint32_t length; /**< length of names */
} arguments; } 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 */ ecma_external_pointer_t external_function; /**< external function */
} u; } u;
} ecma_extended_object_t; } ecma_extended_object_t;
+1 -22
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); 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)) switch (ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (property_p))
{ {
case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */ 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_INSTANTIATED_MASK_32_63: /* an integer (bit-mask) */
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION:
{ {
break; break;
} }
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: default:
{
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 */
{ {
JERRY_UNREACHABLE (); JERRY_UNREACHABLE ();
break; break;
@@ -237,42 +237,42 @@ ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this ar
{ {
/* 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);
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, ecma_object_t *function_p = ecma_create_object (prototype_obj_p,
0, obj_size,
ECMA_OBJECT_TYPE_BOUND_FUNCTION); ECMA_OBJECT_TYPE_BOUND_FUNCTION);
ecma_deref_object (prototype_obj_p); ecma_deref_object (prototype_obj_p);
/* 7. */ ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) function_p;
ecma_value_t *target_function_prop_p;
target_function_prop_p = ecma_create_internal_property (function_p,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION);
/* 7. */
ecma_object_t *this_arg_obj_p = ecma_get_object_from_value (this_arg); 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. */ /* 8. */
ecma_value_t *bound_this_prop_p; ext_function_p->u.bound_function.args_length = args_length;
bound_this_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS); ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
const ecma_length_t arg_count = arguments_number;
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]); *args_p = ecma_copy_value_if_not_object (arguments_list_p[0]);
}
else
{
*bound_this_prop_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
} }
if (arg_count > 1) if (arguments_number > 1)
{ {
ecma_collection_header_t *bound_args_collection_p; for (ecma_length_t i = 1; i < arguments_number; i++)
bound_args_collection_p = ecma_new_values_collection (&arguments_list_p[1], arg_count - 1, false); {
++args_p;
ecma_value_t *bound_args_prop_p; *args_p = ecma_copy_value_if_not_object (arguments_list_p[i]);
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);
} }
/* /*
@@ -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_ERROR (get_len_value));
JERRY_ASSERT (ecma_is_value_number (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 */ /* 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); ecma_free_value (get_len_value);
/* 15.b */ /* 15.b */
@@ -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_get_object_type (obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
} /* ecma_is_constructor */ } /* 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. * 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); JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
/* 1. */ /* 1. */
ecma_value_t *target_function_prop_p; ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
target_function_prop_p = ecma_get_internal_property (func_obj_p,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION);
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. */ /* 3. */
ret_value = ecma_op_object_has_instance (target_func_obj_p, value); 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; JERRY_CONTEXT (is_direct_eval_form_call) = false;
/* 2-3. */ /* 2-3. */
ecma_value_t *target_function_prop_p; ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
target_function_prop_p = ecma_get_internal_property (func_obj_p,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION);
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. */ /* 4. */
ecma_value_t *bound_args_prop_p = ecma_find_internal_property (func_obj_p, ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
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);
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; args_length--;
bound_arg_list_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_header_t, *bound_args_prop_p); ecma_length_t merged_args_list_len = args_length + arguments_list_len;
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;
JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t); 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, memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t));
bound_arg_list_p, memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t));
arguments_list_p,
arguments_list_len);
/* 5. */ /* 5. */
ret_value = ecma_op_function_call (target_func_obj_p, 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); JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
/* 1. */ /* 1. */
ecma_value_t *target_function_prop_p; ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
target_function_prop_p = ecma_get_internal_property (func_obj_p,
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION);
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. */ /* 2. */
if (!ecma_is_constructor (ecma_make_object_value (target_func_obj_p))) 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 else
{ {
/* 4. */ /* 4. */
ecma_value_t *bound_args_prop_p; ecma_length_t args_length = ext_function_p->u.bound_function.args_length;
bound_args_prop_p = ecma_find_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS);
if (bound_args_prop_p != NULL) JERRY_ASSERT (args_length > 0);
if (args_length > 1)
{ {
ecma_collection_header_t *bound_arg_list_p; ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
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); args_length--;
ecma_length_t merged_args_list_len = args_length + arguments_list_len;
ecma_length_t merged_args_list_len = bound_arg_list_p->unit_number + arguments_list_len;
JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t); 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, memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t));
bound_arg_list_p, memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t));
arguments_list_p,
arguments_list_len);
/* 5. */ /* 5. */
ret_value = ecma_op_function_construct (target_func_obj_p, ret_value = ecma_op_function_construct (target_func_obj_p,