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
This commit is contained in:
Zoltan Herczeg
2016-09-23 10:06:36 +02:00
committed by GitHub
parent 547647af13
commit 0ad347b97f
3 changed files with 82 additions and 54 deletions
+15 -3
View File
@@ -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;
/**
@@ -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);
@@ -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);