diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index ca3af7887f..3fa3398689 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -583,8 +583,6 @@ ecma_try_to_give_back_some_memory (jmem_try_give_memory_back_severity_t severity JERRY_ASSERT (severity == JMEM_TRY_GIVE_MEMORY_BACK_SEVERITY_HIGH); /* Freeing as much memory as we currently can */ - ecma_lcache_invalidate_all (); - ecma_gc_run (); } } /* ecma_try_to_give_back_some_memory */ diff --git a/jerry-core/ecma/base/ecma-helpers-string.c b/jerry-core/ecma/base/ecma-helpers-string.c index 79c60f916a..a773fcd145 100644 --- a/jerry-core/ecma/base/ecma-helpers-string.c +++ b/jerry-core/ecma/base/ecma-helpers-string.c @@ -527,7 +527,6 @@ ecma_copy_or_ref_ecma_string (ecma_string_t *string_p) /**< string descriptor */ if (unlikely (string_p->refs_and_container >= ECMA_STRING_MAX_REF)) { /* First trying to free unreachable objects that maybe refer to the string */ - ecma_lcache_invalidate_all (); ecma_gc_run (); if (string_p->refs_and_container >= ECMA_STRING_MAX_REF) diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index c513bc6f44..4277b04b49 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -586,8 +586,6 @@ ecma_create_named_data_property (ecma_object_t *object_p, /**< object */ name_p = ecma_copy_or_ref_ecma_string (name_p); - ecma_lcache_invalidate (object_p, name_p, NULL); - ecma_property_value_t value; value.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); @@ -614,8 +612,6 @@ ecma_create_named_accessor_property (ecma_object_t *object_p, /**< object */ name_p = ecma_copy_or_ref_ecma_string (name_p); - ecma_lcache_invalidate (object_p, name_p, NULL); - ecma_property_value_t value; ECMA_SET_POINTER (value.getter_setter_pair.getter_p, get_p); ECMA_SET_POINTER (value.getter_setter_pair.setter_p, set_p); @@ -636,9 +632,9 @@ ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in JERRY_ASSERT (obj_p != NULL); JERRY_ASSERT (name_p != NULL); - ecma_property_t *property_p; + ecma_property_t *property_p = ecma_lcache_lookup (obj_p, name_p); - if (ecma_lcache_lookup (obj_p, name_p, &property_p)) + if (property_p != NULL) { return property_p; } @@ -649,14 +645,23 @@ ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in if (prop_iter_p != NULL && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP) { - property_p = ecma_property_hashmap_find ((ecma_property_hashmap_t *) prop_iter_p, name_p); - ecma_lcache_insert (obj_p, name_p, property_p); + ecma_string_t *property_real_name_p; + property_p = ecma_property_hashmap_find ((ecma_property_hashmap_t *) prop_iter_p, + name_p, + &property_real_name_p); + + if (property_p != NULL + && !ecma_is_property_lcached (property_p)) + { + ecma_lcache_insert (obj_p, property_real_name_p, property_p); + } return property_p; } #endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */ property_p = NULL; + ecma_string_t *property_name_p = NULL; uint32_t steps = 0; @@ -670,8 +675,8 @@ ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in if (prop_pair_p->names_cp[0] != ECMA_NULL_POINTER) { - ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, - prop_pair_p->names_cp[0]); + property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + prop_pair_p->names_cp[0]); if (ecma_compare_ecma_strings (name_p, property_name_p)) { @@ -682,8 +687,8 @@ ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in if (prop_pair_p->names_cp[1] != ECMA_NULL_POINTER) { - ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, - prop_pair_p->names_cp[1]); + property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + prop_pair_p->names_cp[1]); if (ecma_compare_ecma_strings (name_p, property_name_p)) { @@ -703,7 +708,11 @@ ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in ecma_property_hashmap_create (obj_p); } - ecma_lcache_insert (obj_p, name_p, property_p); + if (property_p != NULL + && !ecma_is_property_lcached (property_p)) + { + ecma_lcache_insert (obj_p, property_name_p, property_p); + } return property_p; } /* ecma_find_named_property */ @@ -875,12 +884,18 @@ ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to case ECMA_PROPERTY_TYPE_NAMEDDATA: { ecma_free_named_data_property (object_p, property_p); - ecma_lcache_invalidate (object_p, name_p, property_p); + if (ecma_is_property_lcached (property_p)) + { + ecma_lcache_invalidate (object_p, name_p, property_p); + } break; } case ECMA_PROPERTY_TYPE_NAMEDACCESSOR: { - ecma_lcache_invalidate (object_p, name_p, property_p); + if (ecma_is_property_lcached (property_p)) + { + ecma_lcache_invalidate (object_p, name_p, property_p); + } break; } case ECMA_PROPERTY_TYPE_INTERNAL: @@ -1270,7 +1285,7 @@ ecma_is_property_lcached (ecma_property_t *prop_p) /**< property */ /** * Set value of flag indicating whether the property is registered in LCache */ -void +inline void __attr_always_inline___ ecma_set_property_lcached (ecma_property_t *prop_p, /**< property */ bool is_lcached) /**< contained (true) or not (false) */ { diff --git a/jerry-core/ecma/base/ecma-init-finalize.c b/jerry-core/ecma/base/ecma-init-finalize.c index ba8c181d27..61f1c8fefc 100644 --- a/jerry-core/ecma/base/ecma-init-finalize.c +++ b/jerry-core/ecma/base/ecma-init-finalize.c @@ -51,7 +51,6 @@ ecma_finalize (void) jmem_unregister_a_try_give_memory_back_callback (ecma_try_to_give_back_some_memory); ecma_finalize_environment (); - ecma_lcache_invalidate_all (); ecma_finalize_builtins (); ecma_gc_run (); } /* ecma_finalize */ diff --git a/jerry-core/ecma/base/ecma-lcache.c b/jerry-core/ecma/base/ecma-lcache.c index a8ea9fc703..34fab5009a 100644 --- a/jerry-core/ecma/base/ecma-lcache.c +++ b/jerry-core/ecma/base/ecma-lcache.c @@ -43,20 +43,15 @@ typedef struct jmem_cpointer_t prop_name_cp; } ecma_lcache_hash_entry_t; -/** - * LCache hash value length, in bits - */ -#define ECMA_LCACHE_HASH_BITS (sizeof (lit_string_hash_t) * JERRY_BITSINBYTE) - /** * Number of rows in LCache's hash table */ -#define ECMA_LCACHE_HASH_ROWS_COUNT (1ull << ECMA_LCACHE_HASH_BITS) +#define ECMA_LCACHE_HASH_ROWS_COUNT 256 /** * Number of entries in a row of LCache's hash table */ -#define ECMA_LCACHE_HASH_ROW_LENGTH (2) +#define ECMA_LCACHE_HASH_ROW_LENGTH 2 /** * LCache's hash table @@ -79,66 +74,31 @@ ecma_lcache_init (void) /** * Invalidate specified LCache entry */ -static void +static inline void __attr_always_inline___ ecma_lcache_invalidate_entry (ecma_lcache_hash_entry_t *entry_p) /**< entry to invalidate */ { JERRY_ASSERT (entry_p != NULL); JERRY_ASSERT (entry_p->object_cp != ECMA_NULL_POINTER); - - ecma_deref_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, - entry_p->object_cp)); + JERRY_ASSERT (entry_p->prop_name_cp != ECMA_NULL_POINTER); + JERRY_ASSERT (entry_p->prop_p != NULL); entry_p->object_cp = ECMA_NULL_POINTER; - ecma_deref_ecma_string (ECMA_GET_NON_NULL_POINTER (ecma_string_t, - entry_p->prop_name_cp)); - - if (entry_p->prop_p != NULL) - { - ecma_set_property_lcached (entry_p->prop_p, false); - } + ecma_set_property_lcached (entry_p->prop_p, false); } /* ecma_lcache_invalidate_entry */ -#endif /* !CONFIG_ECMA_LCACHE_DISABLE */ /** - * Invalidate all entries in LCache - */ -void -ecma_lcache_invalidate_all (void) -{ -#ifndef CONFIG_ECMA_LCACHE_DISABLE - for (uint32_t row_index = 0; row_index < ECMA_LCACHE_HASH_ROWS_COUNT; row_index++) - { - for (uint32_t entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++) - { - if (ecma_lcache_hash_table[ row_index ][ entry_index ].object_cp != ECMA_NULL_POINTER) - { - ecma_lcache_invalidate_entry (&ecma_lcache_hash_table[ row_index ][ entry_index ]); - } - } - } -#endif /* !CONFIG_ECMA_LCACHE_DISABLE */ -} /* ecma_lcache_invalidate_all */ - -#ifndef CONFIG_ECMA_LCACHE_DISABLE -/** - * Invalidate entries of LCache's row that correspond to given (object, property) pair + * Compute the row index of object / property name pair + * + * @return row index */ -static void -ecma_lcache_invalidate_row_for_object_property_pair (uint32_t row_index, /**< index of the row */ - unsigned int object_cp, /**< compressed pointer - * to an object */ - ecma_property_t *property_p) /**< pointer to the - * object's property */ +static inline size_t __attr_always_inline___ +ecma_lcache_row_idx (jmem_cpointer_t object_cp, /**< compressed pointer to object */ + const ecma_string_t *prop_name_p) /**< proeprty name */ { - for (uint32_t entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++) - { - if (ecma_lcache_hash_table[ row_index ][ entry_index ].object_cp == object_cp - && ecma_lcache_hash_table[ row_index ][ entry_index ].prop_p == property_p) - { - ecma_lcache_invalidate_entry (&ecma_lcache_hash_table[ row_index ][ entry_index ]); - } - } -} /* ecma_lcache_invalidate_row_for_object_property_pair */ + /* Randomize the hash of the property name with the object pointer using a xor operation, + * so properties of different objects with the same name can be cached effectively. */ + return (size_t) ((ecma_string_hash (prop_name_p) ^ object_cp) & (ECMA_LCACHE_HASH_ROWS_COUNT - 1)); +} /* ecma_lcache_row_idx */ #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ /** @@ -146,51 +106,26 @@ ecma_lcache_invalidate_row_for_object_property_pair (uint32_t row_index, /**< in */ void ecma_lcache_insert (ecma_object_t *object_p, /**< object */ - ecma_string_t *prop_name_p, /**< property's name */ - ecma_property_t *prop_p) /**< pointer to associated property or NULL - * (NULL indicates that the object doesn't have property - * with the name specified) */ + ecma_string_t *prop_name_p, /**< property name */ + ecma_property_t *prop_p) /**< property */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (prop_name_p != NULL); + JERRY_ASSERT (prop_p != NULL && !ecma_is_property_lcached (prop_p)); + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA + || ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); #ifndef CONFIG_ECMA_LCACHE_DISABLE - prop_name_p = ecma_copy_or_ref_ecma_string (prop_name_p); - - lit_string_hash_t hash_key = ecma_string_hash (prop_name_p); + jmem_cpointer_t object_cp; - if (prop_p != NULL) - { - if (unlikely (ecma_is_property_lcached (prop_p))) - { - int32_t entry_index; - for (entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++) - { - if (ecma_lcache_hash_table[hash_key][entry_index].object_cp != ECMA_NULL_POINTER - && ecma_lcache_hash_table[hash_key][entry_index].prop_p == prop_p) - { -#ifndef JERRY_NDEBUG - ecma_object_t *obj_in_entry_p; - obj_in_entry_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, - ecma_lcache_hash_table[hash_key][entry_index].object_cp); - JERRY_ASSERT (obj_in_entry_p == object_p); -#endif /* !JERRY_NDEBUG */ - break; - } - } + ECMA_SET_NON_NULL_POINTER (object_cp, object_p); - JERRY_ASSERT (entry_index != ECMA_LCACHE_HASH_ROW_LENGTH); - ecma_lcache_invalidate_entry (&ecma_lcache_hash_table[hash_key][entry_index]); - } - - JERRY_ASSERT (!ecma_is_property_lcached (prop_p)); - ecma_set_property_lcached (prop_p, true); - } + ecma_lcache_hash_entry_t *entries_p = ecma_lcache_hash_table[ecma_lcache_row_idx (object_cp, prop_name_p)]; int32_t entry_index; for (entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++) { - if (ecma_lcache_hash_table[hash_key][entry_index].object_cp == ECMA_NULL_POINTER) + if (entries_p[entry_index].object_cp == ECMA_NULL_POINTER) { break; } @@ -198,122 +133,112 @@ ecma_lcache_insert (ecma_object_t *object_p, /**< object */ if (entry_index == ECMA_LCACHE_HASH_ROW_LENGTH) { - /* No empty entry was found, invalidating the whole row */ - for (uint32_t i = 0; i < ECMA_LCACHE_HASH_ROW_LENGTH; i++) + /* Invalidate the last entry. */ + ecma_lcache_invalidate_entry (entries_p + ECMA_LCACHE_HASH_ROW_LENGTH - 1); + + /* Shift other entries towards the end. */ + for (uint32_t i = ECMA_LCACHE_HASH_ROW_LENGTH - 1; i > 0; i--) { - ecma_lcache_invalidate_entry (&ecma_lcache_hash_table[hash_key][i]); + entries_p[i] = entries_p[i - 1]; } entry_index = 0; } - ecma_ref_object (object_p); - ECMA_SET_NON_NULL_POINTER (ecma_lcache_hash_table[ hash_key ][ entry_index ].object_cp, object_p); - ECMA_SET_NON_NULL_POINTER (ecma_lcache_hash_table[ hash_key ][ entry_index ].prop_name_cp, prop_name_p); - ecma_lcache_hash_table[ hash_key ][ entry_index ].prop_p = prop_p; -#else /* CONFIG_ECMA_LCACHE_DISABLE */ - (void) prop_p; + ecma_lcache_hash_entry_t *entry_p = entries_p + entry_index; + ECMA_SET_NON_NULL_POINTER (entry_p->object_cp, object_p); + ECMA_SET_NON_NULL_POINTER (entry_p->prop_name_cp, prop_name_p); + entry_p->prop_p = prop_p; + + ecma_set_property_lcached (entry_p->prop_p, true); #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ } /* ecma_lcache_insert */ /** * Lookup property in the LCache * - * @return true - if (object, property name) pair is registered in LCache, - * false - probably, not registered. + * @return a pointer to an ecma_property_t if the lookup is successful + * NULL otherwise */ -inline bool __attr_always_inline___ +inline ecma_property_t * __attr_always_inline___ ecma_lcache_lookup (ecma_object_t *object_p, /**< object */ - const ecma_string_t *prop_name_p, /**< property's name */ - ecma_property_t **prop_p_p) /**< [out] if return value is true, - * then here will be pointer to property, - * if the object contains property with specified name, - * or, otherwise - NULL; - * if return value is false, - * then the output parameter is not set */ + const ecma_string_t *prop_name_p) /**< property's name */ { -#ifndef CONFIG_ECMA_LCACHE_DISABLE - lit_string_hash_t hash_key = ecma_string_hash (prop_name_p); + JERRY_ASSERT (object_p != NULL); + JERRY_ASSERT (prop_name_p != NULL); - unsigned int object_cp; +#ifndef CONFIG_ECMA_LCACHE_DISABLE + jmem_cpointer_t object_cp; ECMA_SET_NON_NULL_POINTER (object_cp, object_p); - for (uint32_t i = 0; i < ECMA_LCACHE_HASH_ROW_LENGTH; i++) + ecma_lcache_hash_entry_t *entry_p = ecma_lcache_hash_table[ecma_lcache_row_idx (object_cp, prop_name_p)]; + ecma_lcache_hash_entry_t *entry_end_p = entry_p + ECMA_LCACHE_HASH_ROW_LENGTH; + + while (entry_p < entry_end_p) { - if (ecma_lcache_hash_table[hash_key][i].object_cp == object_cp) + if (entry_p->object_cp == object_cp) { ecma_string_t *entry_prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, - ecma_lcache_hash_table[hash_key][i].prop_name_cp); + entry_p->prop_name_cp); JERRY_ASSERT (prop_name_p->hash == entry_prop_name_p->hash); if (ECMA_STRING_GET_CONTAINER (prop_name_p) == ECMA_STRING_GET_CONTAINER (entry_prop_name_p) && prop_name_p->u.common_field == entry_prop_name_p->u.common_field) { - ecma_property_t *prop_p = ecma_lcache_hash_table[hash_key][i].prop_p; - JERRY_ASSERT (prop_p == NULL || ecma_is_property_lcached (prop_p)); + ecma_property_t *prop_p = entry_p->prop_p; + JERRY_ASSERT (prop_p != NULL && ecma_is_property_lcached (prop_p)); - *prop_p_p = prop_p; - - return true; + return prop_p; } else { - /* may be equal but it is long to compare it here */ + /* They can be equal, but generic string comparison is too costly. */ } } + entry_p++; } -#else /* CONFIG_ECMA_LCACHE_DISABLE */ - (void) object_p; - (void) prop_name_p; - (void) prop_p_p; #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ - return false; + return NULL; } /* ecma_lcache_lookup */ /** * Invalidate LCache entries associated with given object and property name / property - * - * Note: - * Either property name argument or property argument should be NULL, - * and another should be non-NULL. - * In case property name argument is NULL, property's name is taken - * from property's description. */ void ecma_lcache_invalidate (ecma_object_t *object_p, /**< object */ - ecma_string_t *prop_name_p, /**< property's name (See also: Note) */ - ecma_property_t *prop_p) /**< property (See also: Note) */ + ecma_string_t *prop_name_p, /**< property's name */ + ecma_property_t *prop_p) /**< property */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (prop_name_p != NULL); + JERRY_ASSERT (prop_p != NULL && ecma_is_property_lcached (prop_p)); + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA + || ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); #ifndef CONFIG_ECMA_LCACHE_DISABLE - if (prop_p != NULL) - { - JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA - || ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); + jmem_cpointer_t object_cp; + ECMA_SET_NON_NULL_POINTER (object_cp, object_p); - bool is_cached = ecma_is_property_lcached (prop_p); + ecma_lcache_hash_entry_t *entry_p = ecma_lcache_hash_table[ecma_lcache_row_idx (object_cp, prop_name_p)]; - if (!is_cached) + for (uint32_t entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++) + { + if (entry_p->object_cp != ECMA_NULL_POINTER && entry_p->prop_p == prop_p) { + JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_string_t, + entry_p->prop_name_cp) == prop_name_p); + JERRY_ASSERT (entry_p->object_cp == object_cp); + + ecma_lcache_invalidate_entry (entry_p); return; } - - ecma_set_property_lcached (prop_p, false); + entry_p++; } - unsigned int object_cp; - ECMA_SET_NON_NULL_POINTER (object_cp, object_p); - - lit_string_hash_t hash_key = ecma_string_hash (prop_name_p); - - /* Property's name has was computed. - * Given (object, property name) pair should be in the row corresponding to computed hash. - */ - ecma_lcache_invalidate_row_for_object_property_pair (hash_key, object_cp, prop_p); + /* The property must be present. */ + JERRY_UNREACHABLE (); #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ } /* ecma_lcache_invalidate */ diff --git a/jerry-core/ecma/base/ecma-lcache.h b/jerry-core/ecma/base/ecma-lcache.h index 6471501473..4cf1f6e37c 100644 --- a/jerry-core/ecma/base/ecma-lcache.h +++ b/jerry-core/ecma/base/ecma-lcache.h @@ -24,9 +24,8 @@ */ extern void ecma_lcache_init (void); -extern void ecma_lcache_invalidate_all (void); extern void ecma_lcache_insert (ecma_object_t *, ecma_string_t *, ecma_property_t *); -extern bool ecma_lcache_lookup (ecma_object_t *, const ecma_string_t *, ecma_property_t **); +extern ecma_property_t *ecma_lcache_lookup (ecma_object_t *, const ecma_string_t *); extern void ecma_lcache_invalidate (ecma_object_t *, ecma_string_t *, ecma_property_t *); /** diff --git a/jerry-core/ecma/base/ecma-property-hashmap.c b/jerry-core/ecma/base/ecma-property-hashmap.c index c193982185..ca8e244a08 100644 --- a/jerry-core/ecma/base/ecma-property-hashmap.c +++ b/jerry-core/ecma/base/ecma-property-hashmap.c @@ -402,7 +402,8 @@ ecma_property_hashmap_delete (ecma_object_t *object_p, /**< object */ */ ecma_property_t * ecma_property_hashmap_find (ecma_property_hashmap_t *hashmap_p, /**< hashmap */ - ecma_string_t *name_p) /**< property name */ + ecma_string_t *name_p, /**< property name */ + ecma_string_t **property_real_name_p) /**< [out] property real name */ { #ifndef JERRY_NDEBUG /* A sanity check in debug mode: a named property must be present @@ -481,6 +482,7 @@ ecma_property_hashmap_find (ecma_property_hashmap_t *hashmap_p, /**< hashmap */ #ifndef JERRY_NDEBUG JERRY_ASSERT (property_found); #endif /* !JERRY_NDEBUG */ + *property_real_name_p = property_name_p; return property_pair_p->header.types + offset; } } diff --git a/jerry-core/ecma/base/ecma-property-hashmap.h b/jerry-core/ecma/base/ecma-property-hashmap.h index 0370a79ffd..3aa4333145 100644 --- a/jerry-core/ecma/base/ecma-property-hashmap.h +++ b/jerry-core/ecma/base/ecma-property-hashmap.h @@ -59,7 +59,7 @@ extern void ecma_property_hashmap_insert (ecma_object_t *, ecma_string_t *, ecma extern void ecma_property_hashmap_delete (ecma_object_t *, ecma_string_t *, ecma_property_t *); #ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE -extern ecma_property_t *ecma_property_hashmap_find (ecma_property_hashmap_t *, ecma_string_t *); +extern ecma_property_t *ecma_property_hashmap_find (ecma_property_hashmap_t *, ecma_string_t *, ecma_string_t **); #endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */ /** diff --git a/jerry-core/ecma/operations/ecma-get-put-value.c b/jerry-core/ecma/operations/ecma-get-put-value.c index 6601b0662b..b6feee4010 100644 --- a/jerry-core/ecma/operations/ecma-get-put-value.c +++ b/jerry-core/ecma/operations/ecma-get-put-value.c @@ -75,83 +75,69 @@ ecma_op_get_value_lex_env_base (ecma_object_t *ref_base_lex_env_p, /**< referenc * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_op_get_value_object_base (ecma_reference_t ref) /**< ECMA-reference */ +ecma_op_get_value_object_base (ecma_value_t base, /**< base value */ + ecma_string_t *property_name_p) /**< property name */ { - const ecma_value_t base = ref.base; - const bool is_unresolvable_reference = ecma_is_value_undefined (base); - const bool has_primitive_base = (ecma_is_value_boolean (base) - || ecma_is_value_number (base) - || ecma_is_value_string (base)); - const bool has_object_base = (ecma_is_value_object (base) - && !(ecma_is_lexical_environment (ecma_get_object_from_value (base)))); - const bool is_property_reference = has_primitive_base || has_object_base; - - JERRY_ASSERT (!is_unresolvable_reference); - JERRY_ASSERT (is_property_reference); - - ecma_string_t *referenced_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, - ref.referenced_name_cp); - // 4.a - if (!has_primitive_base) + if (ecma_is_value_object (base)) { // 4.b case 1 - ecma_object_t *obj_p = ecma_get_object_from_value (base); JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); - return ecma_op_object_get (obj_p, referenced_name_p); + return ecma_op_object_get (obj_p, property_name_p); } - else - { - // 4.b case 2 - ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); - // 1. - ECMA_TRY_CATCH (obj_base, ecma_op_to_object (base), ret_value); + JERRY_ASSERT (ecma_is_value_boolean (base) + || ecma_is_value_number (base) + || ecma_is_value_string (base)); - ecma_object_t *obj_p = ecma_get_object_from_value (obj_base); - JERRY_ASSERT (obj_p != NULL - && !ecma_is_lexical_environment (obj_p)); + // 4.b case 2 + ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); + + // 1. + ECMA_TRY_CATCH (obj_base, ecma_op_to_object (base), ret_value); + ecma_object_t *obj_p = ecma_get_object_from_value (obj_base); + JERRY_ASSERT (obj_p != NULL + && !ecma_is_lexical_environment (obj_p)); - // 2. - ecma_property_t *prop_p = ecma_op_object_get_property (obj_p, referenced_name_p); + // 2. + ecma_property_t *prop_p = ecma_op_object_get_property (obj_p, property_name_p); - if (prop_p == NULL) + if (prop_p == NULL) + { + // 3. + ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + } + else if (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA) + { + // 4. + ret_value = ecma_copy_value (ecma_get_named_data_property_value (prop_p)); + } + else + { + // 5. + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); + + ecma_object_t *obj_p = ecma_get_named_accessor_property_getter (prop_p); + + // 6. + if (obj_p == NULL) { - // 3. ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); } - else if (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA) - { - // 4. - ret_value = ecma_copy_value (ecma_get_named_data_property_value (prop_p)); - } else { - // 5. - JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); - - ecma_object_t *obj_p = ecma_get_named_accessor_property_getter (prop_p); - - // 6. - if (obj_p == NULL) - { - ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); - } - else - { - // 7. - ret_value = ecma_op_function_call (obj_p, base, NULL, 0); - } + // 7. + ret_value = ecma_op_function_call (obj_p, base, NULL, 0); } + } - ECMA_FINALIZE (obj_base); + ECMA_FINALIZE (obj_base); - return ret_value; - } + return ret_value; } /* ecma_op_get_value_object_base */ /** diff --git a/jerry-core/ecma/operations/ecma-lex-env.h b/jerry-core/ecma/operations/ecma-lex-env.h index 627daf91d8..2615a3d97e 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.h +++ b/jerry-core/ecma/operations/ecma-lex-env.h @@ -40,7 +40,7 @@ extern ecma_object_t *ecma_get_global_environment (void); /* ECMA-262 v5, 8.7.1 and 8.7.2 */ extern ecma_value_t ecma_op_get_value_lex_env_base (ecma_object_t *, ecma_string_t *, bool); -extern ecma_value_t ecma_op_get_value_object_base (ecma_reference_t); +extern ecma_value_t ecma_op_get_value_object_base (ecma_value_t, ecma_string_t *); extern ecma_value_t ecma_op_put_value_lex_env_base (ecma_object_t *, ecma_string_t *, bool, ecma_value_t); /* ECMA-262 v5, Table 17. Abstract methods of Environment Records */ diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 9e9f6ef9cf..0a0d5d0a92 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -177,9 +177,9 @@ ecma_op_object_get_own_property (ecma_object_t *obj_p, /**< the object */ && !ecma_is_lexical_environment (obj_p)); JERRY_ASSERT (property_name_p != NULL); - ecma_property_t *prop_p = NULL; + ecma_property_t *prop_p = ecma_lcache_lookup (obj_p, property_name_p); - if (likely (ecma_lcache_lookup (obj_p, property_name_p, &prop_p))) + if (likely (prop_p != NULL)) { return prop_p; } diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 0af11b9acf..b6321b08de 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -24,6 +24,7 @@ #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-helpers.h" +#include "ecma-lcache.h" #include "ecma-lex-env.h" #include "ecma-objects.h" #include "ecma-objects-general.h" @@ -65,31 +66,40 @@ static ecma_compiled_code_t *__program = NULL; */ static ecma_value_t vm_op_get_value (ecma_value_t object, /**< base object */ - ecma_value_t property, /**< property name */ - bool is_strict) /**< strict mode */ + ecma_value_t property) /**< property name */ { if (unlikely (ecma_is_value_undefined (object) || ecma_is_value_null (object))) { return ecma_raise_type_error (ECMA_ERR_MSG ("")); } - ecma_value_t completion_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); + ecma_value_t prop_to_string_result = ecma_op_to_string (property); - ECMA_TRY_CATCH (property_val, - ecma_op_to_string (property), - completion_value); + if (ecma_is_value_error (prop_to_string_result)) + { + return prop_to_string_result; + } - ecma_string_t *property_p = ecma_get_string_from_value (property_val); + ecma_string_t *property_name_p = ecma_get_string_from_value (prop_to_string_result); - ecma_reference_t reference = ecma_make_reference (object, property_p, is_strict); + if (ecma_is_value_object (object)) + { + ecma_object_t *object_p = ecma_get_object_from_value (object); - completion_value = ecma_op_get_value_object_base (reference); + ecma_property_t *property_p = ecma_lcache_lookup (object_p, property_name_p); - ecma_free_reference (reference); + if (property_p != NULL && + ECMA_PROPERTY_GET_TYPE (property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA) + { + ecma_deref_ecma_string (property_name_p); + return ecma_fast_copy_value (ecma_get_named_data_property_value (property_p)); + } + } - ECMA_FINALIZE (property_val); + ecma_value_t get_value_result = ecma_op_get_value_object_base (object, property_name_p); - return completion_value; + ecma_deref_ecma_string (property_name_p); + return get_value_result; } /* vm_op_get_value */ /** @@ -1145,8 +1155,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ case VM_OC_PROP_POST_DECR: { last_completion_value = vm_op_get_value (left_value, - right_value, - is_strict); + right_value); if (ecma_is_value_error (last_completion_value)) {