From bcf3396f26e0797ccc4969ba2d0e468cd00de5a2 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Thu, 3 Sep 2015 21:54:54 +0300 Subject: [PATCH] Lazy instantiation of a function object's 'length' and 'prototype' properties. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- .../ecma/operations/ecma-function-object.cpp | 207 +++++++++++++----- .../ecma/operations/ecma-function-object.h | 4 + jerry-core/ecma/operations/ecma-objects.cpp | 8 +- 3 files changed, 163 insertions(+), 56 deletions(-) diff --git a/jerry-core/ecma/operations/ecma-function-object.cpp b/jerry-core/ecma/operations/ecma-function-object.cpp index 3ddfb6119..2b945f227 100644 --- a/jerry-core/ecma/operations/ecma-function-object.cpp +++ b/jerry-core/ecma/operations/ecma-function-object.cpp @@ -260,71 +260,23 @@ ecma_op_create_function_object (ecma_collection_header_t *formal_params_collecti first_instr_pos); // 14. - ecma_number_t* len_p = ecma_alloc_number (); - *len_p = ecma_uint32_to_number (formal_params_collection_p != NULL ? formal_params_collection_p->unit_number : 0); - // 15. - ecma_property_descriptor_t length_prop_desc = ecma_make_empty_property_descriptor (); - length_prop_desc.is_value_defined = true; - length_prop_desc.value = ecma_make_number_value (len_p); - - ecma_string_t* magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); - ecma_completion_value_t completion = ecma_op_object_define_own_property (f, - magic_string_length_p, - &length_prop_desc, - false); - ecma_deref_ecma_string (magic_string_length_p); - - JERRY_ASSERT (ecma_is_completion_value_normal_true (completion) - || ecma_is_completion_value_normal_false (completion)); - - ecma_dealloc_number (len_p); - len_p = NULL; - // 16. - ecma_object_t *proto_p = ecma_op_create_object_object_noarg (); - // 17. - ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); - { - prop_desc.is_value_defined = true; - prop_desc.value = ecma_make_object_value (f); - - prop_desc.is_writable_defined = true; - prop_desc.is_writable = true; - - prop_desc.is_enumerable_defined = true; - prop_desc.is_enumerable = false; - - prop_desc.is_configurable_defined = true; - prop_desc.is_configurable = true; - } - - ecma_string_t *magic_string_constructor_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR); - ecma_op_object_define_own_property (proto_p, - magic_string_constructor_p, - &prop_desc, - false); - ecma_deref_ecma_string (magic_string_constructor_p); - // 18. - prop_desc.value = ecma_make_object_value (proto_p); - prop_desc.is_configurable = false; - ecma_string_t *magic_string_prototype_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); - ecma_op_object_define_own_property (f, - magic_string_prototype_p, - &prop_desc, - false); - ecma_deref_ecma_string (magic_string_prototype_p); - - ecma_deref_object (proto_p); + /* + * 'length' and 'prototype' properties are instantiated lazily + * + * See also: ecma_op_function_object_get_own_property + * ecma_op_function_try_lazy_instantiate_property + */ // 19. if (is_strict) { ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER); - prop_desc = ecma_make_empty_property_descriptor (); + ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); { prop_desc.is_enumerable_defined = true; prop_desc.is_enumerable = false; @@ -359,6 +311,151 @@ ecma_op_create_function_object (ecma_collection_header_t *formal_params_collecti return f; } /* ecma_op_create_function_object */ +/** + * Lazy instantation of non-builtin ecma function object's properties + * + * Warning: + * Only non-configurable properties could be instantiated lazily in this function, + * as configurable properties could be deleted and it would be incorrect + * to reinstantiate them in the function in second time. + * + * @return pointer to newly instantiated property, if a property was instantiated, + * NULL - otherwise + */ +static ecma_property_t * +ecma_op_function_try_lazy_instantiate_property (ecma_object_t *obj_p, /**< the function object */ + ecma_string_t *property_name_p) /**< property name */ +{ + JERRY_ASSERT (!ecma_get_object_is_builtin (obj_p)); + + ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); + + bool is_length_property = ecma_compare_ecma_strings (magic_string_length_p, property_name_p); + + ecma_deref_ecma_string (magic_string_length_p); + + if (is_length_property) + { + /* ECMA-262 v5, 13.2, 14-15 */ + + // 14 + ecma_number_t *len_p = ecma_alloc_number (); + + ecma_property_t *formal_parameters_prop_p = ecma_get_internal_property (obj_p, + ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS); + ecma_collection_header_t *formal_parameters_p; + formal_parameters_p = ECMA_GET_POINTER (ecma_collection_header_t, + formal_parameters_prop_p->u.internal_property.value); + *len_p = ecma_uint32_to_number (formal_parameters_p != NULL ? formal_parameters_p->unit_number : 0); + + // 15 + ecma_property_t *length_prop_p = ecma_create_named_data_property (obj_p, + property_name_p, + false, + false, + false); + + ecma_named_data_property_assign_value (obj_p, length_prop_p, ecma_make_number_value (len_p)); + + ecma_dealloc_number (len_p); + + JERRY_ASSERT (!ecma_is_property_configurable (length_prop_p)); + return length_prop_p; + } + + ecma_string_t *magic_string_prototype_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); + + bool is_prototype_property = ecma_compare_ecma_strings (magic_string_prototype_p, property_name_p); + + ecma_deref_ecma_string (magic_string_prototype_p); + + if (is_prototype_property) + { + /* ECMA-262 v5, 13.2, 16-18 */ + + // 16. + ecma_object_t *proto_p = ecma_op_create_object_object_noarg (); + + // 17. + ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); + { + prop_desc.is_value_defined = true; + prop_desc.value = ecma_make_object_value (obj_p); + + prop_desc.is_writable_defined = true; + prop_desc.is_writable = true; + + prop_desc.is_enumerable_defined = true; + prop_desc.is_enumerable = false; + + prop_desc.is_configurable_defined = true; + prop_desc.is_configurable = true; + } + + ecma_string_t *magic_string_constructor_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR); + ecma_op_object_define_own_property (proto_p, + magic_string_constructor_p, + &prop_desc, + false); + ecma_deref_ecma_string (magic_string_constructor_p); + + // 18. + ecma_property_t *prototype_prop_p = ecma_create_named_data_property (obj_p, + property_name_p, + true, + false, + false); + + ecma_named_data_property_assign_value (obj_p, prototype_prop_p, ecma_make_object_value (proto_p)); + + ecma_deref_object (proto_p); + + JERRY_ASSERT (!ecma_is_property_configurable (prototype_prop_p)); + return prototype_prop_p; + } + + return NULL; +} /* ecma_op_function_try_lazy_instantiate_property */ + +/** + * Implementation-defined extension of [[GetOwnProperty]] ecma function object's operation + * + * Note: + * The [[GetOwnProperty]] is used only for lazy property instantiation, + * i.e. externally visible behaviour of [[GetOwnProperty]] is specification-defined + * + * @return pointer to a property - if it already existed + * or was lazy instantiated in context of + * current invocation, + * NULL (i.e. ecma-undefined) - otherwise. + */ +ecma_property_t* +ecma_op_function_object_get_own_property (ecma_object_t *obj_p, /**< the function object */ + ecma_string_t *property_name_p) /**< property name */ +{ + JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION); + + ecma_property_t *prop_p = ecma_op_general_object_get_own_property (obj_p, property_name_p); + + if (prop_p != NULL) + { + return prop_p; + } + else if (!ecma_get_object_is_builtin (obj_p)) + { + prop_p = ecma_op_function_try_lazy_instantiate_property (obj_p, property_name_p); + + /* + * Only non-configurable properties could be instantiated lazily in the function, + * as configurable properties could be deleted and it would be incorrect + * to reinstantiate them in the function in second time. + */ + JERRY_ASSERT (prop_p == NULL || !ecma_is_property_configurable (prop_p)); + } + + return prop_p; +} /* ecma_op_function_object_get_own_property */ + /** * External function object creation operation. * diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index bad581d1a..b9045532d 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -44,6 +44,10 @@ ecma_op_function_call (ecma_object_t *func_obj_p, ecma_value_t this_arg_value, ecma_collection_header_t *arg_collection_p); +extern ecma_property_t* +ecma_op_function_object_get_own_property (ecma_object_t *obj_p, + ecma_string_t *property_name_p); + extern ecma_completion_value_t ecma_op_function_call_array_args (ecma_object_t *func_obj_p, ecma_value_t this_arg_value, diff --git a/jerry-core/ecma/operations/ecma-objects.cpp b/jerry-core/ecma/operations/ecma-objects.cpp index b82920283..9455e55a6 100644 --- a/jerry-core/ecma/operations/ecma-objects.cpp +++ b/jerry-core/ecma/operations/ecma-objects.cpp @@ -112,7 +112,6 @@ ecma_op_object_get_own_property_longpath (ecma_object_t *obj_p, /**< the object { case ECMA_OBJECT_TYPE_GENERAL: case ECMA_OBJECT_TYPE_ARRAY: - case ECMA_OBJECT_TYPE_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION: @@ -122,6 +121,13 @@ ecma_op_object_get_own_property_longpath (ecma_object_t *obj_p, /**< the object break; } + case ECMA_OBJECT_TYPE_FUNCTION: + { + prop_p = ecma_op_function_object_get_own_property (obj_p, property_name_p); + + break; + } + case ECMA_OBJECT_TYPE_STRING: { prop_p = ecma_op_string_object_get_own_property (obj_p, property_name_p);