From 5c852ab6fbb0d04ab78d50b6e94819a28a150792 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Thu, 2 Jun 2016 03:56:36 -0700 Subject: [PATCH] Optimize LCache operation. The cache stores only real properties now, because storing NULLs has little benefit according to tests. Since only real properties are stored now, there is no need to create real references to objects and property names, which reduces the keeping of dead objects after garbage collection. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/ecma/base/ecma-gc.c | 2 - jerry-core/ecma/base/ecma-helpers-string.c | 1 - jerry-core/ecma/base/ecma-helpers.c | 47 ++-- jerry-core/ecma/base/ecma-init-finalize.c | 1 - jerry-core/ecma/base/ecma-lcache.c | 235 ++++++------------ jerry-core/ecma/base/ecma-lcache.h | 3 +- jerry-core/ecma/base/ecma-property-hashmap.c | 4 +- jerry-core/ecma/base/ecma-property-hashmap.h | 2 +- .../ecma/operations/ecma-get-put-value.c | 100 ++++---- jerry-core/ecma/operations/ecma-lex-env.h | 2 +- jerry-core/ecma/operations/ecma-objects.c | 4 +- jerry-core/vm/vm.c | 37 +-- 12 files changed, 185 insertions(+), 253 deletions(-) diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index ca3af7887..3fa339868 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 79c60f916..a773fcd14 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 c513bc6f4..4277b04b4 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 ba8c181d2..61f1c8fef 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 a8ea9fc70..34fab5009 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 + * Compute the row index of object / property name pair + * + * @return row index */ -void -ecma_lcache_invalidate_all (void) +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 */ { -#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 - */ -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 */ -{ - 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); + jmem_cpointer_t object_cp; - lit_string_hash_t hash_key = ecma_string_hash (prop_name_p); + ECMA_SET_NON_NULL_POINTER (object_cp, object_p); - 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; - } - } - - 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); - - bool is_cached = ecma_is_property_lcached (prop_p); - - if (!is_cached) - { - return; - } - - ecma_set_property_lcached (prop_p, false); - } - - unsigned int object_cp; + jmem_cpointer_t object_cp; ECMA_SET_NON_NULL_POINTER (object_cp, object_p); - lit_string_hash_t hash_key = ecma_string_hash (prop_name_p); + ecma_lcache_hash_entry_t *entry_p = ecma_lcache_hash_table[ecma_lcache_row_idx (object_cp, 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); + 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; + } + entry_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 647150147..4cf1f6e37 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 c19398218..ca8e244a0 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 0370a79ff..3aa433314 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 6601b0662..b6feee401 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); + } + + JERRY_ASSERT (ecma_is_value_boolean (base) + || ecma_is_value_number (base) + || ecma_is_value_string (base)); + + // 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, property_name_p); + + 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 { - // 4.b case 2 - ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); + // 5. + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR); - // 1. - ECMA_TRY_CATCH (obj_base, ecma_op_to_object (base), ret_value); + ecma_object_t *obj_p = ecma_get_named_accessor_property_getter (prop_p); - 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); - - if (prop_p == NULL) + // 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); - - return ret_value; } + + ECMA_FINALIZE (obj_base); + + 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 627daf91d..2615a3d97 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 9e9f6ef9c..0a0d5d0a9 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 0af11b9ac..b6321b08d 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)) {