Reduce the memory consumption of function objects. (#1954)
Several properties of strict and bound functions are moved to lazy property instantiation. The memory consumption of bound functions are also reduced when only a this is present. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
committed by
Dániel Bátyai
parent
82a94d0f88
commit
e897858c64
@@ -353,10 +353,8 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */
|
|||||||
|
|
||||||
ecma_free_value (parse_status);
|
ecma_free_value (parse_status);
|
||||||
|
|
||||||
is_strict = ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0);
|
|
||||||
ecma_object_t *lex_env_p = ecma_get_global_environment ();
|
ecma_object_t *lex_env_p = ecma_get_global_environment ();
|
||||||
ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p,
|
ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p,
|
||||||
is_strict,
|
|
||||||
bytecode_data_p);
|
bytecode_data_p);
|
||||||
ecma_bytecode_deref (bytecode_data_p);
|
ecma_bytecode_deref (bytecode_data_p);
|
||||||
|
|
||||||
|
|||||||
@@ -336,12 +336,23 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
|
|||||||
|
|
||||||
ecma_gc_set_object_visited (target_func_obj_p, true);
|
ecma_gc_set_object_visited (target_func_obj_p, true);
|
||||||
|
|
||||||
ecma_length_t args_length = ext_function_p->u.bound_function.args_length;
|
ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this;
|
||||||
|
|
||||||
|
if (!ecma_is_value_integer_number (args_len_or_this))
|
||||||
|
{
|
||||||
|
if (ecma_is_value_object (args_len_or_this))
|
||||||
|
{
|
||||||
|
ecma_gc_set_object_visited (ecma_get_object_from_value (args_len_or_this), true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this);
|
||||||
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
|
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
|
||||||
|
|
||||||
JERRY_ASSERT (args_length > 0);
|
JERRY_ASSERT (args_length > 0);
|
||||||
|
|
||||||
for (ecma_length_t i = 0; i < args_length; i++)
|
for (ecma_integer_value_t i = 0; i < args_length; i++)
|
||||||
{
|
{
|
||||||
if (ecma_is_value_object (args_p[i]))
|
if (ecma_is_value_object (args_p[i]))
|
||||||
{
|
{
|
||||||
@@ -659,15 +670,25 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */
|
|||||||
if (object_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
|
if (object_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
|
||||||
{
|
{
|
||||||
ecma_extended_object_t *ext_function_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_len_or_this = ext_function_p->u.bound_function.args_len_or_this;
|
||||||
|
|
||||||
|
if (!ecma_is_value_integer_number (args_len_or_this))
|
||||||
|
{
|
||||||
|
ecma_free_value_if_not_object (args_len_or_this);
|
||||||
|
ecma_dealloc_extended_object (ext_function_p, sizeof (ecma_extended_object_t));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this);
|
||||||
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
|
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
|
||||||
|
|
||||||
for (ecma_length_t i = 0; i < args_length; i++)
|
for (ecma_integer_value_t i = 0; i < args_length; i++)
|
||||||
{
|
{
|
||||||
ecma_free_value_if_not_object (args_p[i]);
|
ecma_free_value_if_not_object (args_p[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t args_size = args_length * sizeof (ecma_value_t);
|
size_t args_size = ((size_t) args_length) * sizeof (ecma_value_t);
|
||||||
ecma_dealloc_extended_object (ext_function_p, sizeof (ecma_extended_object_t) + args_size);
|
ecma_dealloc_extended_object (ext_function_p, sizeof (ecma_extended_object_t) + args_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -768,7 +768,7 @@ typedef struct
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
ecma_value_t target_function; /**< target function */
|
ecma_value_t target_function; /**< target function */
|
||||||
ecma_length_t args_length; /**< length of arguments */
|
ecma_value_t args_len_or_this; /**< length of arguments or this value */
|
||||||
} bound_function;
|
} bound_function;
|
||||||
|
|
||||||
ecma_external_handler_t external_handler_cb; /**< external function */
|
ecma_external_handler_t external_handler_cb; /**< external function */
|
||||||
|
|||||||
@@ -1337,29 +1337,41 @@ ecma_string_raw_chars (const ecma_string_t *string_p, /**< ecma-string */
|
|||||||
} /* ecma_string_raw_chars */
|
} /* ecma_string_raw_chars */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether ecma string is empty or not
|
* Checks whether the string equals to the magic string id.
|
||||||
*
|
*
|
||||||
* @return true - if empty
|
* @return true - if the string equals to the magic string id
|
||||||
* false - otherwise
|
* false - otherwise
|
||||||
*/
|
*/
|
||||||
bool
|
inline bool __attr_always_inline___
|
||||||
ecma_string_is_empty (const ecma_string_t *str_p) /**< ecma-string */
|
ecma_compare_ecma_string_to_magic_id (const ecma_string_t *string_p, /**< property name */
|
||||||
|
lit_magic_string_id_t id) /**< magic string id */
|
||||||
{
|
{
|
||||||
return (ECMA_STRING_GET_CONTAINER (str_p) == ECMA_STRING_CONTAINER_MAGIC_STRING
|
return (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING
|
||||||
&& str_p->u.magic_string_id == LIT_MAGIC_STRING__EMPTY);
|
&& string_p->u.magic_string_id == id);
|
||||||
|
} /* ecma_compare_ecma_string_to_magic_id */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether ecma string is empty or not
|
||||||
|
*
|
||||||
|
* @return true - if the string is an empty string
|
||||||
|
* false - otherwise
|
||||||
|
*/
|
||||||
|
inline bool __attr_always_inline___
|
||||||
|
ecma_string_is_empty (const ecma_string_t *string_p) /**< ecma-string */
|
||||||
|
{
|
||||||
|
return ecma_compare_ecma_string_to_magic_id (string_p, LIT_MAGIC_STRING__EMPTY);
|
||||||
} /* ecma_string_is_empty */
|
} /* ecma_string_is_empty */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the string equals to "length".
|
* Checks whether the string equals to "length".
|
||||||
*
|
*
|
||||||
* @return true if the string equals to "length"
|
* @return true - if the string equals to "length"
|
||||||
* false otherwise
|
* false - otherwise
|
||||||
*/
|
*/
|
||||||
inline bool __attr_always_inline___
|
inline bool __attr_always_inline___
|
||||||
ecma_string_is_length (const ecma_string_t *string_p) /**< property name */
|
ecma_string_is_length (const ecma_string_t *string_p) /**< property name */
|
||||||
{
|
{
|
||||||
return (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING
|
return ecma_compare_ecma_string_to_magic_id (string_p, LIT_MAGIC_STRING_LENGTH);
|
||||||
&& string_p->u.magic_string_id == LIT_MAGIC_STRING_LENGTH);
|
|
||||||
} /* ecma_string_is_length */
|
} /* ecma_string_is_length */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -201,7 +201,8 @@ const lit_utf8_byte_t *ecma_string_raw_chars (const ecma_string_t *string_p, lit
|
|||||||
void ecma_init_ecma_string_from_uint32 (ecma_string_t *string_desc_p, uint32_t uint32_number);
|
void ecma_init_ecma_string_from_uint32 (ecma_string_t *string_desc_p, uint32_t uint32_number);
|
||||||
void ecma_init_ecma_length_string (ecma_string_t *string_desc_p);
|
void ecma_init_ecma_length_string (ecma_string_t *string_desc_p);
|
||||||
void ecma_init_ecma_magic_string (ecma_string_t *string_desc_p, lit_magic_string_id_t id);
|
void ecma_init_ecma_magic_string (ecma_string_t *string_desc_p, lit_magic_string_id_t id);
|
||||||
bool ecma_string_is_empty (const ecma_string_t *str_p);
|
bool ecma_compare_ecma_string_to_magic_id (const ecma_string_t *string_p, lit_magic_string_id_t id);
|
||||||
|
bool ecma_string_is_empty (const ecma_string_t *string_p);
|
||||||
bool ecma_string_is_length (const ecma_string_t *string_p);
|
bool ecma_string_is_length (const ecma_string_t *string_p);
|
||||||
|
|
||||||
jmem_cpointer_t ecma_string_to_property_name (ecma_string_t *prop_name_p, ecma_property_t *name_type_p);
|
jmem_cpointer_t ecma_string_to_property_name (ecma_string_t *prop_name_p, ecma_property_t *name_type_p);
|
||||||
|
|||||||
@@ -237,123 +237,64 @@ 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;
|
ecma_length_t args_length = arguments_number;
|
||||||
|
ecma_object_t *function_p;
|
||||||
|
ecma_extended_object_t *ext_function_p;
|
||||||
|
|
||||||
size_t obj_size = sizeof (ecma_extended_object_t) + (args_length * sizeof (ecma_value_t));
|
if (arguments_number == 0
|
||||||
|
|| (arguments_number == 1 && !ecma_is_value_integer_number (arguments_list_p[0])))
|
||||||
|
{
|
||||||
|
args_length = 1;
|
||||||
|
|
||||||
ecma_object_t *function_p = ecma_create_object (prototype_obj_p,
|
function_p = ecma_create_object (prototype_obj_p,
|
||||||
obj_size,
|
sizeof (ecma_extended_object_t),
|
||||||
ECMA_OBJECT_TYPE_BOUND_FUNCTION);
|
ECMA_OBJECT_TYPE_BOUND_FUNCTION);
|
||||||
|
|
||||||
|
/* 8. */
|
||||||
|
ext_function_p = (ecma_extended_object_t *) function_p;
|
||||||
|
ext_function_p->u.bound_function.args_len_or_this = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
|
||||||
|
|
||||||
|
if (arguments_number != 0)
|
||||||
|
{
|
||||||
|
ext_function_p->u.bound_function.args_len_or_this = ecma_copy_value_if_not_object (arguments_list_p[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JERRY_ASSERT (arguments_number > 0);
|
||||||
|
|
||||||
|
size_t obj_size = sizeof (ecma_extended_object_t) + (args_length * sizeof (ecma_value_t));
|
||||||
|
|
||||||
|
function_p = ecma_create_object (prototype_obj_p,
|
||||||
|
obj_size,
|
||||||
|
ECMA_OBJECT_TYPE_BOUND_FUNCTION);
|
||||||
|
|
||||||
|
/* 8. */
|
||||||
|
ext_function_p = (ecma_extended_object_t *) function_p;
|
||||||
|
|
||||||
|
ecma_value_t args_len_or_this = ecma_make_integer_value ((ecma_integer_value_t) args_length);
|
||||||
|
ext_function_p->u.bound_function.args_len_or_this = args_len_or_this;
|
||||||
|
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
|
||||||
|
|
||||||
|
for (ecma_length_t i = 0; i < arguments_number; i++)
|
||||||
|
{
|
||||||
|
*args_p++ = ecma_copy_value_if_not_object (arguments_list_p[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ecma_deref_object (prototype_obj_p);
|
ecma_deref_object (prototype_obj_p);
|
||||||
|
|
||||||
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) function_p;
|
|
||||||
|
|
||||||
/* 7. */
|
/* 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 (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);
|
||||||
|
|
||||||
/* 8. */
|
|
||||||
ext_function_p->u.bound_function.args_length = args_length;
|
|
||||||
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
|
|
||||||
|
|
||||||
*args_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
|
|
||||||
|
|
||||||
if (arguments_number > 0)
|
|
||||||
{
|
|
||||||
*args_p = ecma_copy_value_if_not_object (arguments_list_p[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arguments_number > 1)
|
|
||||||
{
|
|
||||||
for (ecma_length_t i = 1; i < arguments_number; i++)
|
|
||||||
{
|
|
||||||
++args_p;
|
|
||||||
*args_p = ecma_copy_value_if_not_object (arguments_list_p[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type.
|
* [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type.
|
||||||
*
|
*
|
||||||
* See also: ecma_object_get_class_name
|
* See also: ecma_object_get_class_name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 16. */
|
|
||||||
ecma_number_t length = ECMA_NUMBER_ZERO;
|
|
||||||
ecma_string_t *magic_string_length_p = ecma_new_ecma_length_string ();
|
|
||||||
|
|
||||||
/* 15. */
|
|
||||||
if (ecma_object_get_class_name (this_arg_obj_p) == LIT_MAGIC_STRING_FUNCTION_UL)
|
|
||||||
{
|
|
||||||
ecma_value_t get_len_value = ecma_op_object_get (this_arg_obj_p, magic_string_length_p);
|
|
||||||
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (get_len_value));
|
|
||||||
JERRY_ASSERT (ecma_is_value_number (get_len_value));
|
|
||||||
|
|
||||||
/* 15.a */
|
|
||||||
length = ecma_get_number_from_value (get_len_value) - ((ecma_number_t) (args_length - 1));
|
|
||||||
ecma_free_value (get_len_value);
|
|
||||||
|
|
||||||
/* 15.b */
|
|
||||||
if (ecma_number_is_negative (length))
|
|
||||||
{
|
|
||||||
length = ECMA_NUMBER_ZERO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 17. */
|
|
||||||
ecma_value_t completion = ecma_builtin_helper_def_prop (function_p,
|
|
||||||
magic_string_length_p,
|
|
||||||
ecma_make_number_value (length),
|
|
||||||
false, /* Writable */
|
|
||||||
false, /* Enumerable */
|
|
||||||
false, /* Configurable */
|
|
||||||
false); /* Failure handling */
|
|
||||||
|
|
||||||
JERRY_ASSERT (ecma_is_value_boolean (completion));
|
|
||||||
|
|
||||||
ecma_deref_ecma_string (magic_string_length_p);
|
|
||||||
|
|
||||||
/* 19-21. */
|
|
||||||
ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);
|
|
||||||
|
|
||||||
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
|
|
||||||
{
|
|
||||||
prop_desc.is_enumerable_defined = true;
|
|
||||||
prop_desc.is_enumerable = false;
|
|
||||||
|
|
||||||
prop_desc.is_configurable_defined = true;
|
|
||||||
prop_desc.is_configurable = false;
|
|
||||||
|
|
||||||
prop_desc.is_get_defined = true;
|
|
||||||
prop_desc.get_p = thrower_p;
|
|
||||||
|
|
||||||
prop_desc.is_set_defined = true;
|
|
||||||
prop_desc.set_p = thrower_p;
|
|
||||||
}
|
|
||||||
|
|
||||||
ecma_string_t *magic_string_caller_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER);
|
|
||||||
completion = ecma_op_object_define_own_property (function_p,
|
|
||||||
magic_string_caller_p,
|
|
||||||
&prop_desc,
|
|
||||||
false);
|
|
||||||
|
|
||||||
JERRY_ASSERT (ecma_is_value_boolean (completion));
|
|
||||||
|
|
||||||
ecma_deref_ecma_string (magic_string_caller_p);
|
|
||||||
|
|
||||||
ecma_string_t *magic_string_arguments_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
|
|
||||||
completion = ecma_op_object_define_own_property (function_p,
|
|
||||||
magic_string_arguments_p,
|
|
||||||
&prop_desc,
|
|
||||||
false);
|
|
||||||
|
|
||||||
JERRY_ASSERT (ecma_is_value_boolean (completion));
|
|
||||||
|
|
||||||
ecma_deref_ecma_string (magic_string_arguments_p);
|
|
||||||
ecma_deref_object (thrower_p);
|
|
||||||
|
|
||||||
/* 22. */
|
/* 22. */
|
||||||
ret_value = ecma_make_object_value (function_p);
|
ret_value = ecma_make_object_value (function_p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,16 +98,8 @@ ecma_is_constructor (ecma_value_t value) /**< ecma value */
|
|||||||
*/
|
*/
|
||||||
ecma_object_t *
|
ecma_object_t *
|
||||||
ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
|
ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
|
||||||
bool is_decl_in_strict_mode, /**< is function declared in strict mode code? */
|
|
||||||
const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */
|
const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */
|
||||||
{
|
{
|
||||||
bool is_strict_mode_code = is_decl_in_strict_mode;
|
|
||||||
|
|
||||||
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)
|
|
||||||
{
|
|
||||||
is_strict_mode_code = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 1., 4., 13. */
|
/* 1., 4., 13. */
|
||||||
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);
|
||||||
|
|
||||||
@@ -144,46 +136,9 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
|
|||||||
/*
|
/*
|
||||||
* 'length' and 'prototype' properties are instantiated lazily
|
* 'length' and 'prototype' properties are instantiated lazily
|
||||||
*
|
*
|
||||||
* See also: ecma_op_function_try_lazy_instantiate_property
|
* See also: ecma_op_function_try_to_lazy_instantiate_property
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 19. */
|
|
||||||
if (is_strict_mode_code)
|
|
||||||
{
|
|
||||||
ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);
|
|
||||||
|
|
||||||
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
|
|
||||||
{
|
|
||||||
prop_desc.is_enumerable_defined = true;
|
|
||||||
prop_desc.is_enumerable = false;
|
|
||||||
|
|
||||||
prop_desc.is_configurable_defined = true;
|
|
||||||
prop_desc.is_configurable = false;
|
|
||||||
|
|
||||||
prop_desc.is_get_defined = true;
|
|
||||||
prop_desc.get_p = thrower_p;
|
|
||||||
|
|
||||||
prop_desc.is_set_defined = true;
|
|
||||||
prop_desc.set_p = thrower_p;
|
|
||||||
}
|
|
||||||
|
|
||||||
ecma_string_t *magic_string_caller_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER);
|
|
||||||
ecma_op_object_define_own_property (func_p,
|
|
||||||
magic_string_caller_p,
|
|
||||||
&prop_desc,
|
|
||||||
false);
|
|
||||||
ecma_deref_ecma_string (magic_string_caller_p);
|
|
||||||
|
|
||||||
ecma_string_t *magic_string_arguments_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
|
|
||||||
ecma_op_object_define_own_property (func_p,
|
|
||||||
magic_string_arguments_p,
|
|
||||||
&prop_desc,
|
|
||||||
false);
|
|
||||||
ecma_deref_ecma_string (magic_string_arguments_p);
|
|
||||||
|
|
||||||
ecma_deref_object (thrower_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
return func_p;
|
return func_p;
|
||||||
} /* ecma_op_create_function_object */
|
} /* ecma_op_create_function_object */
|
||||||
|
|
||||||
@@ -192,7 +147,7 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
|
|||||||
* adding them to corresponding string collections
|
* adding them to corresponding string collections
|
||||||
*
|
*
|
||||||
* See also:
|
* See also:
|
||||||
* ecma_op_function_try_lazy_instantiate_property
|
* ecma_op_function_try_to_lazy_instantiate_property
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ecma_op_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties into
|
ecma_op_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties into
|
||||||
@@ -237,68 +192,74 @@ ecma_op_function_list_lazy_property_names (bool separate_enumerable, /**< true -
|
|||||||
* NULL - otherwise
|
* NULL - otherwise
|
||||||
*/
|
*/
|
||||||
ecma_property_t *
|
ecma_property_t *
|
||||||
ecma_op_function_try_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */
|
ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */
|
||||||
ecma_string_t *property_name_p) /**< property name */
|
ecma_string_t *property_name_p) /**< property name */
|
||||||
{
|
{
|
||||||
static const char prototype_str_p[] = "prototype";
|
|
||||||
|
|
||||||
JERRY_ASSERT (!ecma_get_object_is_builtin (object_p));
|
JERRY_ASSERT (!ecma_get_object_is_builtin (object_p));
|
||||||
|
|
||||||
ecma_string_container_t container = ECMA_STRING_GET_CONTAINER (property_name_p);
|
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE))
|
||||||
|
{
|
||||||
|
/* ECMA-262 v5, 13.2, 16-18 */
|
||||||
|
|
||||||
/* Check whether the property_name_p is prototype */
|
/* 16. */
|
||||||
if (container == ECMA_STRING_CONTAINER_MAGIC_STRING)
|
ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg ();
|
||||||
{
|
|
||||||
if (property_name_p->u.magic_string_id != LIT_MAGIC_STRING_PROTOTYPE)
|
/* 17. */
|
||||||
{
|
ecma_string_t magic_string_constructor;
|
||||||
return NULL;
|
ecma_init_ecma_magic_string (&magic_string_constructor, LIT_MAGIC_STRING_CONSTRUCTOR);
|
||||||
}
|
|
||||||
|
ecma_property_value_t *constructor_prop_value_p;
|
||||||
|
constructor_prop_value_p = ecma_create_named_data_property (proto_object_p,
|
||||||
|
&magic_string_constructor,
|
||||||
|
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
constructor_prop_value_p->value = ecma_make_object_value (object_p);
|
||||||
|
|
||||||
|
/* 18. */
|
||||||
|
ecma_property_t *prototype_prop_p;
|
||||||
|
ecma_property_value_t *prototype_prop_value_p;
|
||||||
|
prototype_prop_value_p = ecma_create_named_data_property (object_p,
|
||||||
|
property_name_p,
|
||||||
|
ECMA_PROPERTY_FLAG_WRITABLE,
|
||||||
|
&prototype_prop_p);
|
||||||
|
|
||||||
|
prototype_prop_value_p->value = ecma_make_object_value (proto_object_p);
|
||||||
|
|
||||||
|
ecma_deref_object (proto_object_p);
|
||||||
|
|
||||||
|
return prototype_prop_p;
|
||||||
}
|
}
|
||||||
else if (container != ECMA_STRING_CONTAINER_HEAP_UTF8_STRING
|
|
||||||
|| property_name_p->u.utf8_string.size != (sizeof (prototype_str_p) - 1))
|
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_CALLER)
|
||||||
|
|| ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_ARGUMENTS))
|
||||||
{
|
{
|
||||||
return NULL;
|
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
|
||||||
}
|
|
||||||
else
|
const ecma_compiled_code_t *bytecode_data_p;
|
||||||
{
|
bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t,
|
||||||
if (strncmp ((char *) (property_name_p + 1), prototype_str_p, (sizeof (prototype_str_p) - 1)) != 0)
|
ext_func_p->u.function.bytecode_cp);
|
||||||
|
|
||||||
|
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)
|
||||||
{
|
{
|
||||||
return NULL;
|
ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);
|
||||||
|
|
||||||
|
ecma_property_t *caller_prop_p;
|
||||||
|
/* The property_name_p argument contans the name. */
|
||||||
|
ecma_create_named_accessor_property (object_p,
|
||||||
|
property_name_p,
|
||||||
|
thrower_p,
|
||||||
|
thrower_p,
|
||||||
|
ECMA_PROPERTY_FIXED,
|
||||||
|
&caller_prop_p);
|
||||||
|
|
||||||
|
ecma_deref_object (thrower_p);
|
||||||
|
return caller_prop_p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ECMA-262 v5, 13.2, 16-18 */
|
return NULL;
|
||||||
|
} /* ecma_op_function_try_to_lazy_instantiate_property */
|
||||||
/* 16. */
|
|
||||||
ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg ();
|
|
||||||
|
|
||||||
/* 17. */
|
|
||||||
ecma_string_t *magic_string_constructor_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR);
|
|
||||||
|
|
||||||
ecma_property_value_t *constructor_prop_value_p;
|
|
||||||
constructor_prop_value_p = ecma_create_named_data_property (proto_object_p,
|
|
||||||
magic_string_constructor_p,
|
|
||||||
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
constructor_prop_value_p->value = ecma_make_object_value (object_p);
|
|
||||||
|
|
||||||
ecma_deref_ecma_string (magic_string_constructor_p);
|
|
||||||
|
|
||||||
/* 18. */
|
|
||||||
ecma_property_t *prototype_prop_p;
|
|
||||||
ecma_property_value_t *prototype_prop_value_p;
|
|
||||||
prototype_prop_value_p = ecma_create_named_data_property (object_p,
|
|
||||||
property_name_p,
|
|
||||||
ECMA_PROPERTY_FLAG_WRITABLE,
|
|
||||||
&prototype_prop_p);
|
|
||||||
|
|
||||||
prototype_prop_value_p->value = ecma_make_object_value (proto_object_p);
|
|
||||||
|
|
||||||
ecma_deref_object (proto_object_p);
|
|
||||||
|
|
||||||
return prototype_prop_p;
|
|
||||||
} /* ecma_op_function_try_lazy_instantiate_property */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* External function object creation operation.
|
* External function object creation operation.
|
||||||
@@ -555,10 +516,20 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
|
|||||||
ext_function_p->u.bound_function.target_function);
|
ext_function_p->u.bound_function.target_function);
|
||||||
|
|
||||||
/* 4. */
|
/* 4. */
|
||||||
ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
|
ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this;
|
||||||
|
ecma_value_t bound_this_value;
|
||||||
|
ecma_length_t args_length;
|
||||||
|
|
||||||
ecma_value_t bound_this_value = *args_p;
|
if (!ecma_is_value_integer_number (args_len_or_this))
|
||||||
ecma_length_t args_length = ext_function_p->u.bound_function.args_length;
|
{
|
||||||
|
bound_this_value = args_len_or_this;
|
||||||
|
args_length = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bound_this_value = *(ecma_value_t *) (ext_function_p + 1);
|
||||||
|
args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this);
|
||||||
|
}
|
||||||
|
|
||||||
JERRY_ASSERT (args_length > 0);
|
JERRY_ASSERT (args_length > 0);
|
||||||
|
|
||||||
@@ -569,6 +540,8 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
|
|||||||
|
|
||||||
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_value_t *args_p = (ecma_value_t *) (ext_function_p + 1);
|
||||||
|
|
||||||
memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t));
|
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));
|
memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t));
|
||||||
|
|
||||||
@@ -741,7 +714,14 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* 4. */
|
/* 4. */
|
||||||
ecma_length_t args_length = ext_function_p->u.bound_function.args_length;
|
ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this;
|
||||||
|
|
||||||
|
ecma_length_t args_length = 1;
|
||||||
|
|
||||||
|
if (ecma_is_value_integer_number (args_len_or_this))
|
||||||
|
{
|
||||||
|
args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this);
|
||||||
|
}
|
||||||
|
|
||||||
JERRY_ASSERT (args_length > 0);
|
JERRY_ASSERT (args_length > 0);
|
||||||
|
|
||||||
@@ -777,6 +757,85 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
|
|||||||
return ret_value;
|
return ret_value;
|
||||||
} /* ecma_op_function_construct */
|
} /* ecma_op_function_construct */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create specification defined non-configurable properties for bound functions.
|
||||||
|
*
|
||||||
|
* See also:
|
||||||
|
* ECMA-262 v5, 15.3.4.5
|
||||||
|
*
|
||||||
|
* @return pointer property, if one was instantiated,
|
||||||
|
* NULL - otherwise.
|
||||||
|
*/
|
||||||
|
ecma_property_t *
|
||||||
|
ecma_op_bound_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< object */
|
||||||
|
ecma_string_t *property_name_p) /**< property's name */
|
||||||
|
{
|
||||||
|
JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
|
||||||
|
|
||||||
|
if (ecma_string_is_length (property_name_p))
|
||||||
|
{
|
||||||
|
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) object_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);
|
||||||
|
|
||||||
|
ecma_integer_value_t length = 0;
|
||||||
|
|
||||||
|
if (ecma_object_get_class_name (target_func_obj_p) == LIT_MAGIC_STRING_FUNCTION_UL)
|
||||||
|
{
|
||||||
|
/* The property_name_p argument contans the 'length' string. */
|
||||||
|
ecma_value_t get_len_value = ecma_op_object_get (target_func_obj_p, property_name_p);
|
||||||
|
|
||||||
|
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (get_len_value));
|
||||||
|
JERRY_ASSERT (ecma_is_value_integer_number (get_len_value));
|
||||||
|
|
||||||
|
ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this;
|
||||||
|
ecma_integer_value_t args_length = 1;
|
||||||
|
|
||||||
|
if (ecma_is_value_integer_number (args_len_or_this))
|
||||||
|
{
|
||||||
|
args_length = ecma_get_integer_from_value (args_len_or_this);
|
||||||
|
}
|
||||||
|
|
||||||
|
length = ecma_get_integer_from_value (get_len_value) - (args_length - 1);
|
||||||
|
|
||||||
|
if (length < 0)
|
||||||
|
{
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ecma_property_t *len_prop_p;
|
||||||
|
ecma_property_value_t *len_prop_value_p = ecma_create_named_data_property (object_p,
|
||||||
|
property_name_p,
|
||||||
|
ECMA_PROPERTY_FIXED,
|
||||||
|
&len_prop_p);
|
||||||
|
|
||||||
|
len_prop_value_p->value = ecma_make_integer_value (length);
|
||||||
|
return len_prop_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_CALLER)
|
||||||
|
|| ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_ARGUMENTS))
|
||||||
|
{
|
||||||
|
ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);
|
||||||
|
|
||||||
|
ecma_property_t *caller_prop_p;
|
||||||
|
/* The string_p argument contans the name. */
|
||||||
|
ecma_create_named_accessor_property (object_p,
|
||||||
|
property_name_p,
|
||||||
|
thrower_p,
|
||||||
|
thrower_p,
|
||||||
|
ECMA_PROPERTY_FIXED,
|
||||||
|
&caller_prop_p);
|
||||||
|
|
||||||
|
ecma_deref_object (thrower_p);
|
||||||
|
return caller_prop_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
} /* ecma_op_bound_function_try_to_lazy_instantiate_property */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
* @}
|
* @}
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ bool ecma_op_is_callable (ecma_value_t value);
|
|||||||
bool ecma_is_constructor (ecma_value_t value);
|
bool ecma_is_constructor (ecma_value_t value);
|
||||||
|
|
||||||
ecma_object_t *
|
ecma_object_t *
|
||||||
ecma_op_create_function_object (ecma_object_t *scope_p, bool is_decl_in_strict_mode,
|
ecma_op_create_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p);
|
||||||
const ecma_compiled_code_t *bytecode_data_p);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ecma_op_function_list_lazy_property_names (bool separate_enumerable,
|
ecma_op_function_list_lazy_property_names (bool separate_enumerable,
|
||||||
@@ -39,7 +38,7 @@ ecma_op_function_list_lazy_property_names (bool separate_enumerable,
|
|||||||
ecma_collection_header_t *non_enum_collection_p);
|
ecma_collection_header_t *non_enum_collection_p);
|
||||||
|
|
||||||
ecma_property_t *
|
ecma_property_t *
|
||||||
ecma_op_function_try_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p);
|
ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p);
|
||||||
|
|
||||||
ecma_object_t *
|
ecma_object_t *
|
||||||
ecma_op_create_external_function_object (ecma_external_handler_t handler_cb);
|
ecma_op_create_external_function_object (ecma_external_handler_t handler_cb);
|
||||||
@@ -55,6 +54,9 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, const ecma_value_t *argum
|
|||||||
ecma_value_t
|
ecma_value_t
|
||||||
ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value);
|
ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value);
|
||||||
|
|
||||||
|
ecma_property_t *
|
||||||
|
ecma_op_bound_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
* @}
|
* @}
|
||||||
|
|||||||
@@ -231,7 +231,11 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get prototype physical property. */
|
/* Get prototype physical property. */
|
||||||
property_p = ecma_op_function_try_lazy_instantiate_property (object_p, property_name_p);
|
property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p);
|
||||||
|
}
|
||||||
|
else if (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
|
||||||
|
{
|
||||||
|
property_p = ecma_op_bound_function_try_to_lazy_instantiate_property (object_p, property_name_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property_p == NULL)
|
if (property_p == NULL)
|
||||||
@@ -529,7 +533,11 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get prototype physical property. */
|
/* Get prototype physical property. */
|
||||||
property_p = ecma_op_function_try_lazy_instantiate_property (object_p, property_name_p);
|
property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p);
|
||||||
|
}
|
||||||
|
else if (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
|
||||||
|
{
|
||||||
|
property_p = ecma_op_bound_function_try_to_lazy_instantiate_property (object_p, property_name_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property_p == NULL)
|
if (property_p == NULL)
|
||||||
@@ -816,7 +824,11 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get prototype physical property. */
|
/* Get prototype physical property. */
|
||||||
property_p = ecma_op_function_try_lazy_instantiate_property (object_p, property_name_p);
|
property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p);
|
||||||
|
}
|
||||||
|
else if (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)
|
||||||
|
{
|
||||||
|
property_p = ecma_op_bound_function_try_to_lazy_instantiate_property (object_p, property_name_p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -302,10 +302,7 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
|
|||||||
|
|
||||||
if (is_function)
|
if (is_function)
|
||||||
{
|
{
|
||||||
bool is_strict = ((frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0);
|
|
||||||
|
|
||||||
ecma_object_t *func_obj_p = ecma_op_create_function_object (frame_ctx_p->lex_env_p,
|
ecma_object_t *func_obj_p = ecma_op_create_function_object (frame_ctx_p->lex_env_p,
|
||||||
is_strict,
|
|
||||||
bytecode_p);
|
bytecode_p);
|
||||||
|
|
||||||
return ecma_make_object_value (func_obj_p);
|
return ecma_make_object_value (func_obj_p);
|
||||||
|
|||||||
Reference in New Issue
Block a user