From 76ed78089515bfd5cbacfe0f9bae83fae8290009 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Mon, 17 Nov 2014 18:13:09 +0300 Subject: [PATCH] Introducing cache for property by name lookup (LCache). --- src/libecmaobjects/ecma-alloc.c | 5 +- src/libecmaobjects/ecma-globals.h | 6 + src/libecmaobjects/ecma-helpers-string.c | 38 +++ src/libecmaobjects/ecma-helpers.c | 59 +++- src/libecmaobjects/ecma-helpers.h | 5 + src/libecmaobjects/ecma-lcache.c | 302 +++++++++++++++++++++ src/libecmaobjects/ecma-lcache.h | 37 +++ src/libecmaoperations/ecma-init-finalize.c | 3 + src/libecmaoperations/ecma-objects.c | 17 +- 9 files changed, 466 insertions(+), 6 deletions(-) create mode 100644 src/libecmaobjects/ecma-lcache.c create mode 100644 src/libecmaobjects/ecma-lcache.h diff --git a/src/libecmaobjects/ecma-alloc.c b/src/libecmaobjects/ecma-alloc.c index c9abeaec7..64353967c 100644 --- a/src/libecmaobjects/ecma-alloc.c +++ b/src/libecmaobjects/ecma-alloc.c @@ -13,10 +13,11 @@ * limitations under the License. */ -#include "globals.h" #include "ecma-alloc.h" #include "ecma-globals.h" #include "ecma-gc.h" +#include "ecma-lcache.h" +#include "globals.h" #include "mem-poolman.h" JERRY_STATIC_ASSERT (sizeof (ecma_value_t) <= sizeof (uint16_t)); @@ -64,6 +65,8 @@ JERRY_STATIC_ASSERT (sizeof (ecma_label_descriptor_t) == sizeof (uint64_t)); return p ## ecma_type; \ } \ \ + ecma_lcache_invalidate_all (); \ + \ for (ecma_gc_gen_t gen_id = ECMA_GC_GEN_0; \ gen_id < ECMA_GC_GEN_COUNT; \ gen_id++) \ diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index 10a8eb391..4f1cc9a5f 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -274,6 +274,9 @@ typedef struct ecma_property_t /** Attribute 'Configurable' (ecma_property_configurable_value_t) */ unsigned int configurable : 1; + /** Flag indicating whether the property is registered in LCache */ + unsigned int is_lcached : 1; + /** Value */ ecma_value_t value; } named_data_property; @@ -290,6 +293,9 @@ typedef struct ecma_property_t /** Attribute 'Configurable' (ecma_property_configurable_value_t) */ unsigned int configurable : 1; + /** Flag indicating whether the property is registered in LCache */ + unsigned int is_lcached : 1; + /** Compressed pointer to property's getter */ unsigned int get_p : ECMA_POINTER_FIELD_WIDTH; diff --git a/src/libecmaobjects/ecma-helpers-string.c b/src/libecmaobjects/ecma-helpers-string.c index 497cd8110..dba8961cb 100644 --- a/src/libecmaobjects/ecma-helpers-string.c +++ b/src/libecmaobjects/ecma-helpers-string.c @@ -1510,6 +1510,44 @@ ecma_is_string_magic (const ecma_string_t *string_p, /**< ecma-string */ } } /* ecma_is_string_magic */ +/** + * Try to calculate hash of the ecma-string + * + * Note: + * Not all ecma-string containers provide ability to calculate hash. + * For now, only strings stored in literal table support calculating of hash. + * + * Warning: + * Anyway, if ecma-string is hashable, for given length of hash, + * the hash values should always be equal for equal strings + * irrespective of the strings' container type. + * + * If a ecma-string stored in a container of some type is hashable, + * then the ecma-string should always be hashable if stored in container + * of the same type. + * + * @return true - if hash was calculated, + * false - otherwise (the string is not hashable). + */ +bool +ecma_string_try_hash (const ecma_string_t *string_p, /**< ecma-string to calculate hash for */ + uint32_t hash_length_bits, /**< length of hash value, in bits */ + uint32_t *out_hash_p) /**< out: hash value, if calculated */ + +{ + JERRY_ASSERT (hash_length_bits < sizeof (uint32_t) * JERRY_BITSINBYTE); + uint32_t hash_mask = (1u << hash_length_bits); + + if (string_p->container == ECMA_STRING_CONTAINER_LIT_TABLE) + { + *out_hash_p = (string_p->u.lit_index) & hash_mask; + + return true; + } + + return false; +} /* ecma_string_try_hash */ + /** * @} * @} diff --git a/src/libecmaobjects/ecma-helpers.c b/src/libecmaobjects/ecma-helpers.c index c8a10c61d..e3a030698 100644 --- a/src/libecmaobjects/ecma-helpers.c +++ b/src/libecmaobjects/ecma-helpers.c @@ -24,6 +24,7 @@ #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" +#include "ecma-lcache.h" #include "jrt-bit-fields.h" /** @@ -461,10 +462,13 @@ ecma_create_named_data_property (ecma_object_t *obj_p, /**< object */ prop_p->u.named_data_property.enumerable = enumerable; prop_p->u.named_data_property.configurable = configurable; + prop_p->u.named_data_property.is_lcached = false; + prop_p->u.named_data_property.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); - ecma_property_t *list_head_p = ecma_get_property_list (obj_p); + ecma_lcache_invalidate (obj_p, name_p, NULL); + ecma_property_t *list_head_p = ecma_get_property_list (obj_p); ECMA_SET_POINTER(prop_p->next_property_p, list_head_p); ecma_set_property_list (obj_p, prop_p); @@ -502,6 +506,10 @@ ecma_create_named_accessor_property (ecma_object_t *obj_p, /**< object */ prop_p->u.named_accessor_property.enumerable = enumerable; prop_p->u.named_accessor_property.configurable = configurable; + prop_p->u.named_accessor_property.is_lcached = false; + + ecma_lcache_invalidate (obj_p, name_p, NULL); + ecma_property_t *list_head_p = ecma_get_property_list (obj_p); ECMA_SET_POINTER(prop_p->next_property_p, list_head_p); ecma_set_property_list (obj_p, prop_p); @@ -602,12 +610,14 @@ ecma_get_named_data_property (ecma_object_t *obj_p, /**< object to find property * Free the named data property and values it references. */ static void -ecma_free_named_data_property (ecma_object_t *object_p __unused, /**< object the property belongs to */ +ecma_free_named_data_property (ecma_object_t *object_p, /**< object the property belongs to */ ecma_property_t *property_p) /**< the property */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (property_p != NULL && property_p->type == ECMA_PROPERTY_NAMEDDATA); + ecma_lcache_invalidate (object_p, NULL, property_p); + ecma_deref_ecma_string (ECMA_GET_NON_NULL_POINTER (property_p->u.named_data_property.name_p)); ecma_free_value (property_p->u.named_data_property.value, false); @@ -618,12 +628,14 @@ ecma_free_named_data_property (ecma_object_t *object_p __unused, /**< object the * Free the named accessor property and values it references. */ static void -ecma_free_named_accessor_property (ecma_object_t *object_p __unused, /**< object the property belongs to */ +ecma_free_named_accessor_property (ecma_object_t *object_p, /**< object the property belongs to */ ecma_property_t *property_p) /**< the property */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (property_p != NULL && property_p->type == ECMA_PROPERTY_NAMEDACCESSOR); + ecma_lcache_invalidate (object_p, NULL, property_p); + ecma_deref_ecma_string (ECMA_GET_NON_NULL_POINTER (property_p->u.named_accessor_property.name_p)); ecma_dealloc_property (property_p); @@ -805,6 +817,47 @@ ecma_is_property_configurable (ecma_property_t* prop_p) /**< property */ } } /* ecma_is_property_configurable */ +/** + * Check whether the property is registered in LCache + * + * @return true / false + */ +bool +ecma_is_property_lcached (ecma_property_t *prop_p) /**< property */ +{ + JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA + || prop_p->type == ECMA_PROPERTY_NAMEDACCESSOR); + + if (prop_p->type == ECMA_PROPERTY_NAMEDDATA) + { + return prop_p->u.named_data_property.is_lcached; + } + else + { + return prop_p->u.named_accessor_property.is_lcached; + } +} /* ecma_is_property_lcached */ + +/** + * Set value of flag indicating whether the property is registered in LCache + */ +void +ecma_set_property_lcached (ecma_property_t *prop_p, /**< property */ + bool is_lcached) /**< contained (true) or not (false) */ +{ + JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA + || prop_p->type == ECMA_PROPERTY_NAMEDACCESSOR); + + if (prop_p->type == ECMA_PROPERTY_NAMEDDATA) + { + prop_p->u.named_data_property.is_lcached = is_lcached; + } + else + { + prop_p->u.named_accessor_property.is_lcached = is_lcached; + } +} /* ecma_set_property_lcached */ + /** * Construct empty property descriptor, i.e.: * property descriptor with all is_defined flags set to false and the rest - to default value. diff --git a/src/libecmaobjects/ecma-helpers.h b/src/libecmaobjects/ecma-helpers.h index 9adf9493b..68dcab5f7 100644 --- a/src/libecmaobjects/ecma-helpers.h +++ b/src/libecmaobjects/ecma-helpers.h @@ -133,6 +133,7 @@ extern const ecma_char_t* ecma_get_magic_string_zt (ecma_magic_string_id_t id); extern ecma_string_t* ecma_get_magic_string (ecma_magic_string_id_t id); extern bool ecma_is_string_magic (const ecma_string_t *string_p, ecma_magic_string_id_t *out_id_p); extern bool ecma_is_zt_string_magic (const ecma_char_t *zt_string_p, ecma_magic_string_id_t *out_id_p); +extern bool ecma_string_try_hash (const ecma_string_t *string_p, uint32_t hash_length_bits, uint32_t *out_hash_p); /* ecma-helpers-number.c */ extern const ecma_number_t ecma_number_relative_eps; @@ -248,6 +249,10 @@ extern void ecma_delete_property (ecma_object_t *obj_p, ecma_property_t *prop_p) extern bool ecma_is_property_enumerable (ecma_property_t* prop_p); extern bool ecma_is_property_configurable (ecma_property_t* prop_p); +extern bool ecma_is_property_lcached (ecma_property_t *prop_p); +extern void ecma_set_property_lcached (ecma_property_t *prop_p, + bool is_lcached); + extern ecma_property_descriptor_t ecma_make_empty_property_descriptor (void); extern void ecma_free_property_descriptor (ecma_property_descriptor_t *prop_desc_p); diff --git a/src/libecmaobjects/ecma-lcache.c b/src/libecmaobjects/ecma-lcache.c new file mode 100644 index 000000000..734082b69 --- /dev/null +++ b/src/libecmaobjects/ecma-lcache.c @@ -0,0 +1,302 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-gc.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-lcache.h" +#include "jerry-libc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmalcache Property lookup cache + * @{ + */ + +/** + * Entry of LCache hash table + */ +typedef struct +{ + /** Compressed pointer to object (ECMA_NULL_POINTER marks record empty) */ + uint16_t object_cp; + + /** Compressed pointer to property's name */ + uint16_t prop_name_cp; + + /** Compressed pointer to a property of the object */ + uint16_t prop_cp; +} ecma_lcache_hash_entry_t; + +/** + * LCache hash value length, in bits + */ +#define ECMA_LCACHE_HASH_BITS (8) + +/** + * Number of rows in LCache's hash table + */ +#define ECMA_LCACHE_HASH_ROWS_COUNT (1ull << ECMA_LCACHE_HASH_BITS) + +/** + * Number of entries in a row of LCache's hash table + */ +#define ECMA_LCACHE_HASH_ROW_LENGTH (2) + +/** + * LCache's hash table + */ +static ecma_lcache_hash_entry_t ecma_lcache_hash_table[ ECMA_LCACHE_HASH_ROWS_COUNT ][ ECMA_LCACHE_HASH_ROW_LENGTH ]; + +/** + * Initialize LCache + */ +void +ecma_lcache_init (void) +{ + __memset (ecma_lcache_hash_table, 0, sizeof (ecma_lcache_hash_entry_t)); +} /* ecma_lcache_init */ + +/** + * Invalidate specified LCache entry + */ +static void +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 (entry_p->object_cp)); + + entry_p->object_cp = ECMA_NULL_POINTER; + ecma_deref_ecma_string (ECMA_GET_NON_NULL_POINTER (entry_p->prop_name_cp)); + + if (entry_p->prop_cp != ECMA_NULL_POINTER) + { + ecma_set_property_lcached (ECMA_GET_NON_NULL_POINTER (entry_p->prop_cp), false); + } +} /* ecma_lcache_invalidate_entry */ + +/** + * Invalidate all entries in LCache + */ +void +ecma_lcache_invalidate_all (void) +{ + 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 ]); + } + } + } +} /* ecma_lcache_invalidate_all */ + +/** + * 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 */ + unsigned property_cp) /**< compressed 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_cp == property_cp) + { + ecma_lcache_invalidate_entry (&ecma_lcache_hash_table[ row_index ][ entry_index ]); + } + } +} /* ecma_lcache_invalidate_row_for_object_property_pair */ + +/** + * 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); + + uint32_t hash_key; + + if (!ecma_string_try_hash (prop_name_p, ECMA_LCACHE_HASH_BITS, &hash_key)) + { + return; + } + + if (prop_p != NULL) + { + 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, + ecma_copy_or_ref_ecma_string (prop_name_p)); + ECMA_SET_POINTER (ecma_lcache_hash_table[ hash_key ][ entry_index ].prop_cp, prop_p); +} /* ecma_lcache_insert */ + +/** + * Lookup property in the LCache + * + * @return true - if (object, property name) pair is registered in LCache, + * false - otherwise. + */ +bool +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 */ +{ + uint32_t hash_key; + + if (!ecma_string_try_hash (prop_name_p, ECMA_LCACHE_HASH_BITS, &hash_key)) + { + return false; + } + + 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_compare_ecma_strings (prop_name_p, + ECMA_GET_NON_NULL_POINTER (ecma_lcache_hash_table[hash_key][i].prop_name_cp))) + { + ecma_property_t *prop_p = ECMA_GET_POINTER (ecma_lcache_hash_table[hash_key][i].prop_cp); + JERRY_ASSERT (prop_p == NULL || ecma_is_property_lcached (prop_p)); + + *prop_p_p = prop_p; + + return true; + } + } + + return false; +} /* 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_arg_p, /**< property's name (See also: Note) */ + ecma_property_t *prop_p) /**< property (See also: Note) */ +{ + JERRY_ASSERT (object_p != NULL); + JERRY_ASSERT (prop_p != NULL || prop_name_arg_p != NULL); + + ecma_string_t *prop_name_p = NULL; + + if (prop_p != NULL) + { + JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA + || prop_p->type == ECMA_PROPERTY_NAMEDACCESSOR); + + bool is_cached = ecma_is_property_lcached (prop_p); + + if (!is_cached) + { + return; + } + + ecma_set_property_lcached (prop_p, false); + + if (prop_p->type == ECMA_PROPERTY_NAMEDDATA) + { + prop_name_p = ECMA_GET_NON_NULL_POINTER (prop_p->u.named_data_property.name_p); + } + else + { + prop_name_p = ECMA_GET_NON_NULL_POINTER (prop_p->u.named_accessor_property.name_p); + } + } + else + { + prop_name_p = prop_name_arg_p; + } + + unsigned int object_cp, prop_cp; + ECMA_SET_NON_NULL_POINTER (object_cp, object_p); + ECMA_SET_POINTER (prop_cp, prop_p); + + uint32_t hash_key; + + if (!ecma_string_try_hash (prop_name_p, ECMA_LCACHE_HASH_BITS, &hash_key)) + { + /* Property's name hash was not computed, so iterating the whole hash table */ + for (uint32_t row_index = 0; row_index < ECMA_LCACHE_HASH_ROWS_COUNT; row_index++) + { + ecma_lcache_invalidate_row_for_object_property_pair (row_index, object_cp, prop_cp); + } + } + else + { + /* 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_cp); + } +} /* ecma_lcache_invalidate */ + +/** + * @} + * @} + */ diff --git a/src/libecmaobjects/ecma-lcache.h b/src/libecmaobjects/ecma-lcache.h new file mode 100644 index 000000000..38187ef8f --- /dev/null +++ b/src/libecmaobjects/ecma-lcache.h @@ -0,0 +1,37 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMA_LCACHE_H +#define ECMA_LCACHE_H + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmalcache Property lookup cache + * @{ + */ + +extern void ecma_lcache_init (void); +extern void ecma_lcache_invalidate_all (void); +extern void ecma_lcache_insert (ecma_object_t *object_p, ecma_string_t *prop_name_p, ecma_property_t *prop_p); +extern bool ecma_lcache_lookup (ecma_object_t *object_p, const ecma_string_t *prop_name_p, ecma_property_t **prop_p_p); +extern void ecma_lcache_invalidate (ecma_object_t *object_p, ecma_string_t *prop_name_arg_p, ecma_property_t *prop_p); + +/** + * @} + * @} + */ + +#endif /* ECMA_LCACHE_H */ diff --git a/src/libecmaoperations/ecma-init-finalize.c b/src/libecmaoperations/ecma-init-finalize.c index 6e3b797f7..06e7c9d31 100644 --- a/src/libecmaoperations/ecma-init-finalize.c +++ b/src/libecmaoperations/ecma-init-finalize.c @@ -15,6 +15,7 @@ #include "ecma-builtins.h" #include "ecma-helpers.h" +#include "ecma-lcache.h" #include "ecma-operations.h" /** \addtogroup ecma ECMA @@ -32,6 +33,7 @@ ecma_init (void) { ecma_strings_init (); ecma_init_builtins (); + ecma_lcache_init (); } /* ecma_init */ /** @@ -40,6 +42,7 @@ ecma_init (void) void ecma_finalize (void) { + ecma_lcache_invalidate_all (); ecma_finalize_builtins (); } /* ecma_finalize */ diff --git a/src/libecmaoperations/ecma-objects.c b/src/libecmaoperations/ecma-objects.c index f23b9ba2b..03f5ed116 100644 --- a/src/libecmaoperations/ecma-objects.c +++ b/src/libecmaoperations/ecma-objects.c @@ -13,11 +13,12 @@ * limitations under the License. */ +#include "ecma-array-object.h" #include "ecma-builtins.h" #include "ecma-exceptions.h" #include "ecma-globals.h" -#include "ecma-array-object.h" #include "ecma-function-object.h" +#include "ecma-lcache.h" #include "ecma-string-object.h" #include "ecma-objects-arguments.h" #include "ecma-objects-general.h" @@ -82,12 +83,18 @@ 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; + + if (likely (ecma_lcache_lookup (obj_p, property_name_p, &prop_p))) + { + return prop_p; + } + const ecma_object_type_t type = ecma_get_object_type (obj_p); JERRY_ASSERT (type < ECMA_OBJECT_TYPE__COUNT); const bool is_builtin = ecma_get_object_is_builtin (obj_p); - ecma_property_t *prop_p = NULL; typedef ecma_property_t* (*get_own_property_ptr_t) (ecma_object_t *, ecma_string_t *); static const get_own_property_ptr_t get_own_property [ECMA_OBJECT_TYPE__COUNT] = { @@ -111,6 +118,12 @@ ecma_op_object_get_own_property (ecma_object_t *obj_p, /**< the object */ } } + /* + * Property name should be the same as the value passed to ecma_lcache_lookup above, + * or at least hash for the two strings should be either non-computable or the same (see also: ecma_string_try_hash). + */ + ecma_lcache_insert (obj_p, property_name_p, prop_p); + return prop_p; } /* ecma_op_object_get_own_property */