From 0ad347b97fd9a591c992718f960acf76fb8508b3 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Fri, 23 Sep 2016 10:06:36 +0200 Subject: [PATCH] Improve define own property. (#1369) This patch changes define own property to search a property only once. Currently all existing properties are searched at least twice, sometimes three times which is not optimal. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/ecma/base/ecma-globals.h | 18 ++- .../ecma/operations/ecma-objects-general.c | 112 ++++++++++-------- jerry-core/ecma/operations/ecma-objects.c | 6 + 3 files changed, 82 insertions(+), 54 deletions(-) diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index da3016f17..09e3e53b4 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -443,14 +443,25 @@ typedef struct #define ECMA_PROPERTY_SEARCH_DEPTH_LIMIT 128 /** - * Property reference. + * Property reference. It contains the value pointer + * for real, and the value itself for virtual properties. */ typedef union { - ecma_property_value_t *value_p; /**< direct pointer to property value */ - ecma_value_t virtual_value; /**< property value */ + ecma_property_value_t *value_p; /**< property value pointer for real properties */ + ecma_value_t virtual_value; /**< property value for virtual properties */ } ecma_property_ref_t; +/** + * Extended property reference, which also contains the + * property descriptor pointer for real properties. + */ +typedef struct +{ + ecma_property_ref_t property_ref; /**< property reference */ + ecma_property_t *property_p; /**< property descriptor pointer for real properties */ +} ecma_extended_property_ref_t; + /** * Option flags for ecma_op_object_get_property */ @@ -458,6 +469,7 @@ typedef enum { ECMA_PROPERTY_GET_NO_OPTIONS = 0, /**< no option flags for ecma_op_object_get_property */ ECMA_PROPERTY_GET_VALUE = 1u << 0, /**< fill virtual_value field for virtual properties */ + ECMA_PROPERTY_GET_EXT_REFERENCE = 1u << 1, /**< get extended reference to the property */ } ecma_property_get_option_bits_t; /** diff --git a/jerry-core/ecma/operations/ecma-objects-general.c b/jerry-core/ecma/operations/ecma-objects-general.c index b0c0956ac..07ef6a417 100644 --- a/jerry-core/ecma/operations/ecma-objects-general.c +++ b/jerry-core/ecma/operations/ecma-objects-general.c @@ -281,14 +281,14 @@ ecma_op_general_object_default_value (ecma_object_t *obj_p, /**< the object */ * Returned value must be freed with ecma_free_value */ ecma_value_t -ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the object */ +ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p, /**< property name */ const ecma_property_descriptor_t *property_desc_p, /**< property * descriptor */ bool is_throw) /**< flag that controls failure handling */ { - JERRY_ASSERT (obj_p != NULL - && !ecma_is_lexical_environment (obj_p)); + JERRY_ASSERT (object_p != NULL + && !ecma_is_lexical_environment (object_p)); JERRY_ASSERT (property_name_p != NULL); ecma_property_types_t property_desc_type = ECMA_PROPERTY_TYPE_GENERIC; @@ -314,17 +314,18 @@ ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the objec JERRY_ASSERT (property_desc_p->is_writable_defined || !property_desc_p->is_writable); // 1. - ecma_property_ref_t property_ref; + ecma_extended_property_ref_t ext_property_ref; + ecma_property_t current_prop; - ecma_property_t current_prop = ecma_op_object_get_own_property (obj_p, - property_name_p, - &property_ref, - ECMA_PROPERTY_GET_VALUE); + current_prop = ecma_op_object_get_own_property (object_p, + property_name_p, + &ext_property_ref.property_ref, + ECMA_PROPERTY_GET_VALUE | ECMA_PROPERTY_GET_EXT_REFERENCE); if (current_prop == ECMA_PROPERTY_TYPE_NOT_FOUND) { // 3. - if (!ecma_get_object_extensible (obj_p)) + if (!ecma_get_object_extensible (object_p)) { // 2. return ecma_reject (is_throw); @@ -354,7 +355,7 @@ ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the objec prop_attributes = (uint8_t) (prop_attributes | ECMA_PROPERTY_FLAG_WRITABLE); } - ecma_property_value_t *new_prop_value_p = ecma_create_named_data_property (obj_p, + ecma_property_value_t *new_prop_value_p = ecma_create_named_data_property (object_p, property_name_p, prop_attributes, NULL); @@ -379,7 +380,7 @@ ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the objec prop_attributes = (uint8_t) (prop_attributes | ECMA_PROPERTY_FLAG_ENUMERABLE); } - ecma_create_named_accessor_property (obj_p, + ecma_create_named_accessor_property (object_p, property_name_p, property_desc_p->get_p, property_desc_p->set_p, @@ -405,7 +406,7 @@ ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the objec { if (current_property_type == ECMA_PROPERTY_TYPE_VIRTUAL) { - ecma_free_value (property_ref.virtual_value); + ecma_free_value (ext_property_ref.property_ref.virtual_value); } return ecma_reject (is_throw); } @@ -420,12 +421,12 @@ ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the objec || property_desc_p->is_writable || (property_desc_p->is_value_defined && !ecma_op_same_value (property_desc_p->value, - property_ref.virtual_value))) + ext_property_ref.property_ref.virtual_value))) { result = ecma_reject (is_throw); } - ecma_free_value (property_ref.virtual_value); + ecma_free_value (ext_property_ref.property_ref.virtual_value); return result; } @@ -446,7 +447,7 @@ ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the objec && (property_desc_p->is_writable || (property_desc_p->is_value_defined && !ecma_op_same_value (property_desc_p->value, - property_ref.value_p->value)))) + ext_property_ref.property_ref.value_p->value)))) { return ecma_reject (is_throw); } @@ -456,10 +457,12 @@ ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the objec // 11. // a. + ecma_property_value_t *value_p = ext_property_ref.property_ref.value_p; + if ((property_desc_p->is_get_defined - && property_desc_p->get_p != ecma_get_named_accessor_property_getter (property_ref.value_p)) + && property_desc_p->get_p != ecma_get_named_accessor_property_getter (value_p)) || (property_desc_p->is_set_defined - && property_desc_p->set_p != ecma_get_named_accessor_property_setter (property_ref.value_p))) + && property_desc_p->set_p != ecma_get_named_accessor_property_setter (value_p))) { // i., ii. return ecma_reject (is_throw); @@ -476,80 +479,87 @@ ecma_op_general_object_define_own_property (ecma_object_t *obj_p, /**< the objec return ecma_reject (is_throw); } - /* The following implementation can be optimized by directly overwriting - * the fields of current_p if this code path is performance critical. */ - uint8_t prop_attributes = ECMA_PROPERTY_FLAG_CONFIGURABLE; - - if (ecma_is_property_enumerable (current_prop)) - { - prop_attributes = (uint8_t) (prop_attributes | ECMA_PROPERTY_FLAG_ENUMERABLE); - } - - ecma_delete_property (obj_p, property_ref.value_p); + ecma_property_value_t *value_p = ext_property_ref.property_ref.value_p; if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR) { - // b. + JERRY_ASSERT (current_property_type == ECMA_PROPERTY_TYPE_NAMEDDATA); + ecma_free_value_if_not_object (value_p->value); - property_ref.value_p = ecma_create_named_accessor_property (obj_p, - property_name_p, - NULL, - NULL, - prop_attributes); +#ifdef JERRY_CPOINTER_32_BIT + ecma_getter_setter_pointers_t *getter_setter_pair_p; + getter_setter_pair_p = jmem_pools_alloc (sizeof (ecma_getter_setter_pointers_t)); + getter_setter_pair_p->getter_p = JMEM_CP_NULL; + getter_setter_pair_p->setter_p = JMEM_CP_NULL; + ECMA_SET_POINTER (value_p->getter_setter_pair_cp, getter_setter_pair_p); +#else /* !JERRY_CPOINTER_32_BIT */ + value_p->getter_setter_pair.getter_p = JMEM_CP_NULL; + value_p->getter_setter_pair.setter_p = JMEM_CP_NULL; +#endif /* JERRY_CPOINTER_32_BIT */ } else { - // c. - - property_ref.value_p = ecma_create_named_data_property (obj_p, - property_name_p, - prop_attributes, - NULL); + JERRY_ASSERT (current_property_type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); +#ifdef JERRY_CPOINTER_32_BIT + ecma_getter_setter_pointers_t *getter_setter_pair_p; + getter_setter_pair_p = ECMA_GET_POINTER (ecma_getter_setter_pointers_t, + value_p->getter_setter_pair_cp); + jmem_pools_free (getter_setter_pair_p, sizeof (ecma_getter_setter_pointers_t)); +#endif /* JERRY_CPOINTER_32_BIT */ + value_p->value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } + + /* Update flags */ + ecma_property_t prop_flags = *(ext_property_ref.property_p); + prop_flags = (ecma_property_t) (prop_flags & ~(ECMA_PROPERTY_TYPE_MASK | ECMA_PROPERTY_FLAG_WRITABLE)); + prop_flags = (ecma_property_t) (prop_flags | property_desc_type); + *(ext_property_ref.property_p) = prop_flags; } - ecma_property_t *current_p = ecma_find_named_property (obj_p, property_name_p); - - JERRY_ASSERT (ECMA_PROPERTY_VALUE_PTR (current_p) == property_ref.value_p); - // 12. if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDDATA) { - JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*current_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*ext_property_ref.property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); if (property_desc_p->is_value_defined) { - ecma_named_data_property_assign_value (obj_p, property_ref.value_p, property_desc_p->value); + ecma_named_data_property_assign_value (object_p, + ext_property_ref.property_ref.value_p, + property_desc_p->value); } if (property_desc_p->is_writable_defined) { - ecma_set_property_writable_attr (current_p, property_desc_p->is_writable); + ecma_set_property_writable_attr (ext_property_ref.property_p, property_desc_p->is_writable); } } else if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR) { - JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*current_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*ext_property_ref.property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); if (property_desc_p->is_get_defined) { - ecma_set_named_accessor_property_getter (obj_p, property_ref.value_p, property_desc_p->get_p); + ecma_set_named_accessor_property_getter (object_p, + ext_property_ref.property_ref.value_p, + property_desc_p->get_p); } if (property_desc_p->is_set_defined) { - ecma_set_named_accessor_property_setter (obj_p, property_ref.value_p, property_desc_p->set_p); + ecma_set_named_accessor_property_setter (object_p, + ext_property_ref.property_ref.value_p, + property_desc_p->set_p); } } if (property_desc_p->is_enumerable_defined) { - ecma_set_property_enumerable_attr (current_p, property_desc_p->is_enumerable); + ecma_set_property_enumerable_attr (ext_property_ref.property_p, property_desc_p->is_enumerable); } if (property_desc_p->is_configurable_defined) { - ecma_set_property_configurable_attr (current_p, property_desc_p->is_configurable); + ecma_set_property_configurable_attr (ext_property_ref.property_p, property_desc_p->is_configurable); } return ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 9ef463c05..d534ba74b 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -76,6 +76,7 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p)); JERRY_ASSERT (property_name_p != NULL); + JERRY_ASSERT (options == ECMA_PROPERTY_GET_NO_OPTIONS || property_ref_p != NULL); ecma_object_type_t type = ecma_get_object_type (object_p); @@ -178,6 +179,11 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ } } + if (options & ECMA_PROPERTY_GET_EXT_REFERENCE) + { + ((ecma_extended_property_ref_t *) property_ref_p)->property_p = property_p; + } + if (property_ref_p != NULL) { property_ref_p->value_p = ECMA_PROPERTY_VALUE_PTR (property_p);