From 522c7d3f877c3a2c0eb9dcea45758f9574d0f2bb Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Fri, 1 Sep 2017 04:26:35 -0700 Subject: [PATCH] Correctly enumerate function property members. Functions has several built-in non-enumerable properties, and they are correctly ignored during enumeration after this patch. External function prototype is also lazy enumerated. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- .../ecma/operations/ecma-function-object.c | 370 ++++++++++++------ .../ecma/operations/ecma-function-object.h | 30 +- jerry-core/ecma/operations/ecma-objects.c | 63 +-- tests/jerry/es2015/function-properties.js | 46 +++ 4 files changed, 347 insertions(+), 162 deletions(-) create mode 100644 tests/jerry/es2015/function-properties.js diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 81c663f09..546d540dc 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -142,125 +142,6 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ return func_p; } /* ecma_op_create_function_object */ -/** - * List names of a Function object's lazy instantiated properties, - * adding them to corresponding string collections - * - * See also: - * ecma_op_function_try_to_lazy_instantiate_property - */ -void -ecma_op_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties into - * main collection and non-enumerable - * to collection of 'skipped - * non-enumerable' properties, - * false - list all properties into main - * collection. - */ - ecma_collection_header_t *main_collection_p, /**< 'main' collection */ - ecma_collection_header_t *non_enum_collection_p) /**< skipped - * 'non-enumerable' - * collection */ -{ - ecma_collection_header_t *for_enumerable_p = main_collection_p; - JERRY_UNUSED (for_enumerable_p); - - ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; - - ecma_string_t *name_p; - - /* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */ - name_p = ecma_new_ecma_length_string (); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); - - /* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */ - name_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); -} /* ecma_op_function_list_lazy_property_names */ - -/** - * 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 - */ -ecma_property_t * -ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */ - ecma_string_t *property_name_p) /**< property name */ -{ - JERRY_ASSERT (!ecma_get_object_is_builtin (object_p)); - - if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE)) - { - /* 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; - 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; - } - - 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_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) - { - 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; - } - } - - return NULL; -} /* ecma_op_function_try_to_lazy_instantiate_property */ - /** * External function object creation operation. * @@ -291,17 +172,6 @@ ecma_op_create_external_function_object (ecma_external_handler_t handler_cb) /** ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) function_obj_p; ext_func_obj_p->u.external_handler_cb = handler_cb; - ecma_string_t *magic_string_prototype_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); - ecma_builtin_helper_def_prop (function_obj_p, - magic_string_prototype_p, - ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), - true, /* Writable */ - false, /* Enumerable */ - false, /* Configurable */ - false); /* Failure handling */ - - ecma_deref_ecma_string (magic_string_prototype_p); - return function_obj_p; } /* ecma_op_create_external_function_object */ @@ -757,6 +627,118 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ return ret_value; } /* ecma_op_function_construct */ +/** + * 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 + */ +ecma_property_t * +ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< the function object */ + ecma_string_t *property_name_p) /**< property name */ +{ + JERRY_ASSERT (!ecma_get_object_is_builtin (object_p)); + + if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE)) + { + /* 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; + 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; + } + + 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_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) + { + 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; + } + } + + return NULL; +} /* ecma_op_function_try_to_lazy_instantiate_property */ + +/** + * Create specification defined non-configurable properties for external functions. + * + * See also: + * ECMA-262 v5, 15.3.4.5 + * + * @return pointer property, if one was instantiated, + * NULL - otherwise. + */ +ecma_property_t * +ecma_op_external_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_EXTERNAL_FUNCTION); + + if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_PROTOTYPE)) + { + 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_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + return prototype_prop_p; + } + + return NULL; +} /* ecma_op_external_function_try_to_lazy_instantiate_property */ + /** * Create specification defined non-configurable properties for bound functions. * @@ -836,6 +818,134 @@ ecma_op_bound_function_try_to_lazy_instantiate_property (ecma_object_t *object_p return NULL; } /* ecma_op_bound_function_try_to_lazy_instantiate_property */ +/** + * List names of a Function object's lazy instantiated properties, + * adding them to corresponding string collections + * + * See also: + * ecma_op_function_try_to_lazy_instantiate_property + */ +void +ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, /**< functionobject */ + bool separate_enumerable, /**< true - list enumerable properties into + * main collection and non-enumerable + * to collection of 'skipped + * non-enumerable' properties, + * false - list all properties into main + * collection. + */ + ecma_collection_header_t *main_collection_p, /**< 'main' collection */ + ecma_collection_header_t *non_enum_collection_p) /**< skipped + * 'non-enumerable' + * collection */ +{ + JERRY_UNUSED (main_collection_p); + + ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + + /* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */ + ecma_string_t *name_p = ecma_new_ecma_length_string (); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); + + /* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */ + name_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); + + 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) + { + /* 'caller' property is non-enumerable (ECMA-262 v5, 13.2.5) */ + name_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); + + /* 'arguments' property is non-enumerable (ECMA-262 v5, 13.2.5) */ + name_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); + } +} /* ecma_op_function_list_lazy_property_names */ + +/** + * List names of an External Function object's lazy instantiated properties, + * adding them to corresponding string collections + * + * See also: + * ecma_op_external_function_try_to_lazy_instantiate_property + */ +void +ecma_op_external_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties + * into main collection and + * non-enumerable to collection + * of 'skipped non-enumerable' + * properties, + * false - list all properties into + * main collection. + */ + ecma_collection_header_t *main_collection_p, /**< 'main' + * collection */ + ecma_collection_header_t *non_enum_collection_p) /**< skipped + * collection */ +{ + JERRY_UNUSED (main_collection_p); + + ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + + /* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */ + ecma_string_t *name_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); +} /* ecma_op_external_function_list_lazy_property_names */ + +/** + * List names of a Bound Function object's lazy instantiated properties, + * adding them to corresponding string collections + * + * See also: + * ecma_op_bound_function_try_to_lazy_instantiate_property + */ +void +ecma_op_bound_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties + * into main collection and + * non-enumerable to collection + * of 'skipped non-enumerable' + * properties, + * false - list all properties into + * main collection. + */ + ecma_collection_header_t *main_collection_p, /**< 'main' + * collection */ + ecma_collection_header_t *non_enum_collection_p) /**< skipped + * 'non-enumerable' + * collection */ +{ + JERRY_UNUSED (main_collection_p); + + ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + + /* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */ + ecma_string_t *name_p = ecma_new_ecma_length_string (); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); + + /* 'caller' property is non-enumerable (ECMA-262 v5, 13.2.5) */ + name_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); + + /* 'arguments' property is non-enumerable (ECMA-262 v5, 13.2.5) */ + name_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); +} /* ecma_op_bound_function_list_lazy_property_names */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index 392550039..3566ebfd4 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -32,14 +32,6 @@ bool ecma_is_constructor (ecma_value_t value); ecma_object_t * 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, - ecma_collection_header_t *main_collection_p, - ecma_collection_header_t *non_enum_collection_p); - -ecma_property_t * -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); @@ -54,9 +46,31 @@ 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_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p); + +ecma_property_t * +ecma_op_external_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p); + ecma_property_t * ecma_op_bound_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p); +void +ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, + bool separate_enumerable, + ecma_collection_header_t *main_collection_p, + ecma_collection_header_t *non_enum_collection_p); + +void +ecma_op_external_function_list_lazy_property_names (bool separate_enumerable, + ecma_collection_header_t *main_collection_p, + ecma_collection_header_t *non_enum_collection_p); + +void +ecma_op_bound_function_list_lazy_property_names (bool separate_enumerable, + ecma_collection_header_t *main_collection_p, + ecma_collection_header_t *non_enum_collection_p); + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index ee42c7427..335e5d303 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -233,6 +233,10 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ /* Get prototype physical property. */ property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p); } + else if (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) + { + property_p = ecma_op_external_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); @@ -535,6 +539,10 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ /* Get prototype physical property. */ property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p); } + else if (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) + { + property_p = ecma_op_external_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); @@ -826,6 +834,10 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ /* Get prototype physical property. */ property_p = ecma_op_function_try_to_lazy_instantiate_property (object_p, property_name_p); } + else if (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) + { + property_p = ecma_op_external_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); @@ -1361,8 +1373,6 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ switch (type) { case ECMA_OBJECT_TYPE_GENERAL: - case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: - case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { break; } @@ -1378,11 +1388,26 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ } case ECMA_OBJECT_TYPE_FUNCTION: { - ecma_op_function_list_lazy_property_names (is_enumerable_only, + ecma_op_function_list_lazy_property_names (obj_p, + is_enumerable_only, prop_names_p, skipped_non_enumerable_p); break; } + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: + { + ecma_op_external_function_list_lazy_property_names (is_enumerable_only, + prop_names_p, + skipped_non_enumerable_p); + break; + } + case ECMA_OBJECT_TYPE_BOUND_FUNCTION: + { + ecma_op_bound_function_list_lazy_property_names (is_enumerable_only, + prop_names_p, + skipped_non_enumerable_p); + break; + } case ECMA_OBJECT_TYPE_CLASS: { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; @@ -1504,15 +1529,6 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ ecma_append_to_values_collection (skipped_non_enumerable_p, ecma_make_string_value (name_p), true); - - uint8_t hash = (uint8_t) name_p->hash; - uint32_t bitmap_row = (uint32_t) (hash / bitmap_row_size); - uint32_t bitmap_column = (uint32_t) (hash % bitmap_row_size); - - if ((names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) == 0) - { - names_hashes_bitmap[bitmap_row] |= (1u << bitmap_column); - } } ecma_deref_ecma_string (name_p); @@ -1541,7 +1557,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ } } - /* Second pass: collecting properties names into arrays */ + /* Second pass: collecting property names into arrays. */ JMEM_DEFINE_LOCAL_ARRAY (names_p, array_index_named_properties_count + string_named_properties_count, ecma_string_t *); @@ -1622,7 +1638,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ i < array_index_named_properties_count + string_named_properties_count; i++) { - bool is_append; + bool is_append = true; ecma_string_t *name_p = names_p[i]; @@ -1632,16 +1648,12 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if ((names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) == 0) { - /* no name with the hash is in constructed collection */ - is_append = true; - + /* This hash has not been used before (for non-skipped). */ names_hashes_bitmap[bitmap_row] |= (1u << bitmap_column); } else { - /* name with same hash already occured */ - bool is_equal_found = false; - + /* Name with same hash has already occured. */ ecma_collection_iterator_init (&iter, ret_p); while (ecma_collection_iterator_next (&iter)) @@ -1650,10 +1662,14 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if (ecma_compare_ecma_strings (name_p, iter_name_p)) { - is_equal_found = true; + is_append = false; + break; } } + } + if (is_append) + { ecma_collection_iterator_init (&iter, skipped_non_enumerable_p); while (ecma_collection_iterator_next (&iter)) { @@ -1661,11 +1677,10 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if (ecma_compare_ecma_strings (name_p, iter_name_p)) { - is_equal_found = true; + is_append = false; + break; } } - - is_append = !is_equal_found; } if (is_append) diff --git a/tests/jerry/es2015/function-properties.js b/tests/jerry/es2015/function-properties.js new file mode 100644 index 000000000..1ad28ec74 --- /dev/null +++ b/tests/jerry/es2015/function-properties.js @@ -0,0 +1,46 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function getProperties(obj) +{ + var str = ""; + for (name in obj) + { + if (str) + { + str += " " + name; + } + else + { + str = name; + } + } + return str; +} + +var prototype_obj = { dummy:1, length:1, caller:null, + arguments:null, prototype:null }; + +var func = function() {}; + +Object.setPrototypeOf(func, prototype_obj); +assert(getProperties(func) == "dummy caller arguments"); + +var bound_func = (function() {}).bind(null); +Object.setPrototypeOf(bound_func, prototype_obj); +assert(getProperties(bound_func) == "dummy prototype"); + +// 'print' is an external function +Object.setPrototypeOf(print, prototype_obj); +assert(getProperties(print) == "dummy length caller arguments");