From e897858c64097d6c19569b974e44da4e32127649 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Wed, 30 Aug 2017 14:17:35 +0200 Subject: [PATCH] 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 --- jerry-core/api/jerry.c | 2 - jerry-core/ecma/base/ecma-gc.c | 31 +- jerry-core/ecma/base/ecma-globals.h | 2 +- jerry-core/ecma/base/ecma-helpers-string.c | 32 ++- jerry-core/ecma/base/ecma-helpers.h | 3 +- .../ecma-builtin-function-prototype.c | 143 +++------- .../ecma/operations/ecma-function-object.c | 265 +++++++++++------- .../ecma/operations/ecma-function-object.h | 8 +- jerry-core/ecma/operations/ecma-objects.c | 18 +- jerry-core/vm/vm.c | 3 - 10 files changed, 275 insertions(+), 232 deletions(-) diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 0f253148c..5a35032af 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -353,10 +353,8 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */ 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 *func_obj_p = ecma_op_create_function_object (lex_env_p, - is_strict, bytecode_data_p); ecma_bytecode_deref (bytecode_data_p); diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 8e957a2bb..7a4d5aeb7 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -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_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); 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])) { @@ -659,15 +670,25 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ 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_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); - 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]); } - 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); return; } diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 83ac92ec2..c361c1f9c 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -768,7 +768,7 @@ typedef struct struct { 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; ecma_external_handler_t external_handler_cb; /**< external function */ diff --git a/jerry-core/ecma/base/ecma-helpers-string.c b/jerry-core/ecma/base/ecma-helpers-string.c index 1308f1356..6b7cf2db0 100644 --- a/jerry-core/ecma/base/ecma-helpers-string.c +++ b/jerry-core/ecma/base/ecma-helpers-string.c @@ -1337,29 +1337,41 @@ ecma_string_raw_chars (const ecma_string_t *string_p, /**< ecma-string */ } /* 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 */ -bool -ecma_string_is_empty (const ecma_string_t *str_p) /**< ecma-string */ +inline bool __attr_always_inline___ +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 - && str_p->u.magic_string_id == LIT_MAGIC_STRING__EMPTY); + return (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING + && 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 */ /** * Checks whether the string equals to "length". * - * @return true if the string equals to "length" - * false otherwise + * @return true - if the string equals to "length" + * false - otherwise */ inline bool __attr_always_inline___ ecma_string_is_length (const ecma_string_t *string_p) /**< property name */ { - return (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING - && string_p->u.magic_string_id == LIT_MAGIC_STRING_LENGTH); + return ecma_compare_ecma_string_to_magic_id (string_p, LIT_MAGIC_STRING_LENGTH); } /* ecma_string_is_length */ /** diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index f8e98d0c9..35cbbdd41 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -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_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); -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); jmem_cpointer_t ecma_string_to_property_name (ecma_string_t *prop_name_p, ecma_property_t *name_type_p); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c index 32dc90a1f..1bb4d9c84 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c @@ -237,123 +237,64 @@ 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; + 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, - obj_size, - ECMA_OBJECT_TYPE_BOUND_FUNCTION); + function_p = ecma_create_object (prototype_obj_p, + sizeof (ecma_extended_object_t), + 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_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 (ext_function_p->u.bound_function.target_function, 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. * * 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. */ ret_value = ecma_make_object_value (function_p); } diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index a5a1b4f2a..81c663f09 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -98,16 +98,8 @@ ecma_is_constructor (ecma_value_t value) /**< ecma value */ */ ecma_object_t * 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 */ { - 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. */ 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 * - * 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; } /* 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 * * See also: - * ecma_op_function_try_lazy_instantiate_property + * ecma_op_function_try_to_lazy_instantiate_property */ void 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 */ ecma_property_t * -ecma_op_function_try_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */ - ecma_string_t *property_name_p) /**< property name */ +ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */ + ecma_string_t *property_name_p) /**< property name */ { - static const char prototype_str_p[] = "prototype"; - 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 */ - if (container == ECMA_STRING_CONTAINER_MAGIC_STRING) - { - if (property_name_p->u.magic_string_id != LIT_MAGIC_STRING_PROTOTYPE) - { - return NULL; - } + /* 16. */ + ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg (); + + /* 17. */ + ecma_string_t magic_string_constructor; + 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; - } - else - { - if (strncmp ((char *) (property_name_p + 1), prototype_str_p, (sizeof (prototype_str_p) - 1)) != 0) + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + + const ecma_compiled_code_t *bytecode_data_p; + bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, + 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 */ - - /* 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 */ + return NULL; +} /* ecma_op_function_try_to_lazy_instantiate_property */ /** * 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); /* 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; - ecma_length_t args_length = ext_function_p->u.bound_function.args_length; + if (!ecma_is_value_integer_number (args_len_or_this)) + { + 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); @@ -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); + 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_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 { /* 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); @@ -777,6 +757,85 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ return ret_value; } /* 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 */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index a52c5b193..392550039 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -30,8 +30,7 @@ bool ecma_op_is_callable (ecma_value_t value); bool ecma_is_constructor (ecma_value_t value); ecma_object_t * -ecma_op_create_function_object (ecma_object_t *scope_p, bool is_decl_in_strict_mode, - const ecma_compiled_code_t *bytecode_data_p); +ecma_op_create_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p); void 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_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_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_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); + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 6163bf4e0..ee42c7427 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -231,7 +231,11 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ } /* 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) @@ -529,7 +533,11 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ } /* 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) @@ -816,7 +824,11 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ } /* 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); } } diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 893f6ae20..0d69ff004 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -302,10 +302,7 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ 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, - is_strict, bytecode_p); return ecma_make_object_value (func_obj_p);