/** * 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) */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (prop_name_p != NULL); #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; 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); #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ } /* ecma_lcache_invalidate */
/** * Compute the row index of object / property name pair * * @return row index */ static inline size_t __attr_always_inline___ ecma_lcache_row_index (jmem_cpointer_t object_cp, /**< compressed pointer to object */ const ecma_string_t *prop_name_p) /**< proeprty name */ { /* 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_MASK); } /* ecma_lcache_row_index */
/** * Lookup property in the LCache * * @return true - if (object, property name) pair is registered in LCache, * false - probably, not registered. */ inline bool __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 */ { #ifndef CONFIG_ECMA_LCACHE_DISABLE lit_string_hash_t hash_key = ecma_string_hash (prop_name_p); unsigned int object_cp; ECMA_SET_NON_NULL_POINTER (object_cp, object_p); for (uint32_t i = 0; i < ECMA_LCACHE_HASH_ROW_LENGTH; i++) { if (ecma_lcache_hash_table[hash_key][i].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); 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)); *prop_p_p = prop_p; return true; } else { /* may be equal but it is long to compare it here */ } } } #else /* CONFIG_ECMA_LCACHE_DISABLE */ (void) object_p; (void) prop_name_p; (void) prop_p_p; #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ return false; } /* ecma_lcache_lookup */
/** * Lookup property in the LCache * * @return a pointer to an ecma_property_t if the lookup is successful * NULL otherwise */ 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 */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (prop_name_p != NULL); #ifndef CONFIG_ECMA_LCACHE_DISABLE jmem_cpointer_t object_cp; ECMA_SET_NON_NULL_POINTER (object_cp, object_p); size_t row_index = ecma_lcache_row_index (object_cp, ecma_string_hash (prop_name_p)); ecma_lcache_hash_entry_t *entry_p = JERRY_HASH_TABLE_CONTEXT (table) [row_index]; ecma_lcache_hash_entry_t *entry_end_p = entry_p + ECMA_LCACHE_HASH_ROW_LENGTH; ecma_property_t prop_name_type; jmem_cpointer_t prop_name_cp = ecma_string_to_lcache_property_name (prop_name_p, &prop_name_type); while (entry_p < entry_end_p) { if (entry_p->object_cp == object_cp && entry_p->prop_name_cp == prop_name_cp) { ecma_property_t *prop_p = entry_p->prop_p; JERRY_ASSERT (prop_p != NULL && ecma_is_property_lcached (prop_p)); if (ECMA_PROPERTY_GET_NAME_TYPE (*prop_p) == prop_name_type) { return prop_p; } } else { /* They can be equal, but generic string comparison is too costly. */ } entry_p++; } #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ return NULL; } /* ecma_lcache_lookup */
/** * Insert an entry into LCache */ 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) */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (prop_name_p != NULL); #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); 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); } 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) { break; } } 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++) { ecma_lcache_invalidate_entry (&ecma_lcache_hash_table[hash_key][i]); } 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; #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ } /* ecma_lcache_insert */