Add property name hashing support.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2016-04-20 03:38:43 -07:00
parent 02ba19f24d
commit a3b1db3638
7 changed files with 731 additions and 29 deletions

View File

@ -127,6 +127,11 @@
*/
// #define CONFIG_ECMA_LCACHE_DISABLE
/**
* Disable ECMA property hashmap
*/
// #define CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
/**
* Share of newly allocated since last GC objects among all currently allocated objects,
* after achieving which, GC is started upon low severity try-give-memory-back requests.

View File

@ -22,6 +22,7 @@
#include "ecma-gc.h"
#include "ecma-helpers.h"
#include "ecma-lcache.h"
#include "ecma-property-hashmap.h"
#include "jrt.h"
#include "jrt-libc-includes.h"
#include "jrt-bit-fields.h"
@ -372,6 +373,13 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
{
ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);
if (prop_iter_p != NULL
&& ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP)
{
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
while (prop_iter_p != NULL)
{
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
@ -428,6 +436,13 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */
{
ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);
if (prop_iter_p != NULL
&& ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP)
{
ecma_property_hashmap_free (object_p);
prop_iter_p = ecma_get_property_list (object_p);
}
while (prop_iter_p != NULL)
{
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));

View File

@ -226,7 +226,10 @@ typedef enum
ECMA_PROPERTY_TYPE_PROPERTY_PAIR__MAX = ECMA_PROPERTY_TYPE_NAMEDACCESSOR, /**< highest value for
* property pair types. */
ECMA_PROPERTY_TYPE__MAX = ECMA_PROPERTY_TYPE_NAMEDACCESSOR, /**< highest value for property types. */
ECMA_PROPERTY_TYPE_HASHMAP, /**< hash map for fast property access */
ECMA_PROPERTY_TYPE__MAX = ECMA_PROPERTY_TYPE_HASHMAP, /**< highest value for property types. */
} ecma_property_types_t;
/**

View File

@ -19,6 +19,7 @@
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-lcache.h"
#include "ecma-property-hashmap.h"
#include "jrt-bit-fields.h"
#include "byte-code.h"
#include "re-compiler.h"
@ -392,15 +393,32 @@ ecma_get_lex_env_binding_object (const ecma_object_t *object_p) /**< object-boun
static ecma_property_t *
ecma_create_property (ecma_object_t *object_p, /**< the object */
ecma_string_t *name_p, /**< property name */
uint8_t type_and_flags) /**< type and flags, see ecma_property_info_t */
uint8_t type_and_flags, /**< type and flags, see ecma_property_info_t */
ecma_property_value_t value) /**< property value */
{
JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2);
if (object_p->property_list_or_bound_object_cp != ECMA_NULL_POINTER)
mem_cpointer_t *property_list_head_p = &object_p->property_list_or_bound_object_cp;
bool has_hashmap = false;
if (*property_list_head_p != ECMA_NULL_POINTER)
{
/* If the first entry is free (deleted), we simply use its value. */
/* If the first entry is a hashmap, it is skipped. */
ecma_property_header_t *first_property_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
object_p->property_list_or_bound_object_cp);
*property_list_head_p);
if (ECMA_PROPERTY_GET_TYPE (first_property_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP)
{
property_list_head_p = &first_property_p->next_property_cp;
has_hashmap = true;
}
}
if (*property_list_head_p != ECMA_NULL_POINTER)
{
/* If the first entry is free (deleted), it is reused. */
ecma_property_header_t *first_property_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
*property_list_head_p);
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (first_property_p));
@ -415,6 +433,21 @@ ecma_create_property (ecma_object_t *object_p, /**< the object */
JERRY_ASSERT (ECMA_PROPERTY_VALUE_PTR (property_p) == first_property_pair_p->values + 0);
first_property_pair_p->values[0] = value;
/* The property must be fully initialized before ecma_property_hashmap_insert
* is called, because the insert operation may reallocate the hashmap, and
* that triggers garbage collection which scans all properties of all objects.
* A not fully initialized but queued property may cause a crash. */
if (has_hashmap && name_p != NULL)
{
ecma_property_hashmap_insert (object_p,
name_p,
first_property_pair_p,
0);
}
return property_p;
}
}
@ -423,18 +456,30 @@ ecma_create_property (ecma_object_t *object_p, /**< the object */
ecma_property_pair_t *first_property_pair_p = ecma_alloc_property_pair ();
/* Just copy the previous value (no need to decompress, compress). */
first_property_pair_p->header.next_property_cp = object_p->property_list_or_bound_object_cp;
first_property_pair_p->header.next_property_cp = *property_list_head_p;
first_property_pair_p->header.types[0].type_and_flags = ECMA_PROPERTY_TYPE_DELETED;
first_property_pair_p->header.types[1].type_and_flags = type_and_flags;
first_property_pair_p->names_cp[0] = ECMA_NULL_POINTER;
ECMA_SET_POINTER (first_property_pair_p->names_cp[1], name_p);
ecma_set_property_list (object_p, &first_property_pair_p->header);
ECMA_SET_NON_NULL_POINTER (*property_list_head_p, &first_property_pair_p->header);
ecma_property_t *property_p = first_property_pair_p->header.types + 1;
JERRY_ASSERT (ECMA_PROPERTY_VALUE_PTR (property_p) == first_property_pair_p->values + 1);
first_property_pair_p->values[1] = value;
/* See the comment before the other ecma_property_hashmap_insert above. */
if (has_hashmap && name_p != NULL)
{
ecma_property_hashmap_insert (object_p,
name_p,
first_property_pair_p,
1);
}
return property_p;
} /* ecma_create_property */
@ -453,11 +498,10 @@ ecma_create_internal_property (ecma_object_t *object_p, /**< the object */
uint8_t id_byte = (uint8_t) (property_id << ECMA_PROPERTY_FLAG_SHIFT);
uint8_t type_and_flags = (uint8_t) (ECMA_PROPERTY_TYPE_INTERNAL | id_byte);
ecma_property_t *property_p = ecma_create_property (object_p, NULL, type_and_flags);
ecma_property_value_t value;
value.value = ECMA_NULL_POINTER;
ECMA_PROPERTY_VALUE_PTR (property_p)->value = ECMA_NULL_POINTER;
return property_p;
return ecma_create_property (object_p, NULL, type_and_flags, value);
} /* ecma_create_internal_property */
/**
@ -477,6 +521,13 @@ ecma_find_internal_property (ecma_object_t *object_p, /**< object descriptor */
ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);
if (prop_iter_p != NULL
&& ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP)
{
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
while (prop_iter_p != NULL)
{
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
@ -551,13 +602,12 @@ ecma_create_named_data_property (ecma_object_t *object_p, /**< object */
name_p = ecma_copy_or_ref_ecma_string (name_p);
ecma_property_t *property_p = ecma_create_property (object_p, name_p, type_and_flags);
ecma_set_named_data_property_value (property_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));
ecma_lcache_invalidate (object_p, name_p, NULL);
return property_p;
ecma_property_value_t value;
value.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
return ecma_create_property (object_p, name_p, type_and_flags, value);
} /* ecma_create_named_data_property */
/**
@ -588,17 +638,13 @@ ecma_create_named_accessor_property (ecma_object_t *object_p, /**< object */
name_p = ecma_copy_or_ref_ecma_string (name_p);
ecma_property_t *property_p = ecma_create_property (object_p, name_p, type_and_flags);
/*
* Should be performed after linking the property into object's property list, because the setters assert that.
*/
ecma_set_named_accessor_property_getter (object_p, property_p, get_p);
ecma_set_named_accessor_property_setter (object_p, property_p, set_p);
ecma_lcache_invalidate (object_p, name_p, NULL);
return property_p;
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);
return ecma_create_property (object_p, name_p, type_and_flags, value);
} /* ecma_create_named_accessor_property */
/**
@ -621,9 +667,22 @@ ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in
return property_p;
}
ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_p);
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
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);
return property_p;
}
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
property_p = NULL;
ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_p);
uint32_t steps = 0;
while (prop_iter_p != NULL)
{
@ -657,10 +716,17 @@ ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in
}
}
steps++;
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
if (steps > (ECMA_PROPERTY_HASMAP_MINIMUM_SIZE / 4))
{
ecma_property_hashmap_create (obj_p);
}
ecma_lcache_insert (obj_p, name_p, property_p);
return property_p;
@ -884,6 +950,16 @@ ecma_delete_property (ecma_object_t *object_p, /**< object */
{
ecma_property_header_t *cur_prop_p = ecma_get_property_list (object_p);
ecma_property_header_t *prev_prop_p = NULL;
bool has_hashmap = false;
if (cur_prop_p != NULL
&& ECMA_PROPERTY_GET_TYPE (cur_prop_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP)
{
prev_prop_p = cur_prop_p;
cur_prop_p = ECMA_GET_POINTER (ecma_property_header_t,
cur_prop_p->next_property_cp);
has_hashmap = true;
}
while (true)
{
@ -900,13 +976,20 @@ ecma_delete_property (ecma_object_t *object_p, /**< object */
ecma_free_property (object_p, name_p, cur_prop_p->types + i);
prop_pair_p->names_cp[i] = ECMA_NULL_POINTER;
if (name_p != NULL)
{
if (has_hashmap)
{
ecma_property_hashmap_delete (object_p,
name_p,
prop_p);
}
ecma_deref_ecma_string (name_p);
}
prop_pair_p->names_cp[i] = ECMA_NULL_POINTER;
JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2);
if (cur_prop_p->types[1 - i].type_and_flags != ECMA_PROPERTY_TYPE_DELETED)
@ -938,7 +1021,7 @@ ecma_delete_property (ecma_object_t *object_p, /**< object */
} /* ecma_delete_property */
/**
* Check that
* Check whether the object contains a property
*/
static void
ecma_assert_object_contains_the_property (const ecma_object_t *object_p, /**< ecma-object */
@ -947,6 +1030,14 @@ ecma_assert_object_contains_the_property (const ecma_object_t *object_p, /**< ec
#ifndef JERRY_NDEBUG
ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);
JERRY_ASSERT (prop_iter_p != NULL);
if (ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP)
{
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
while (prop_iter_p != NULL)
{
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));

View File

@ -0,0 +1,511 @@
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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-globals.h"
#include "ecma-helpers.h"
#include "ecma-property-hashmap.h"
#include "jrt-libc-includes.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmapropertyhashmap Property hashmap
* @{
*/
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
/**
* Compute the total size of the property hashmap.
*/
#define ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE(max_property_count) \
(sizeof (ecma_property_hashmap_t) + (max_property_count * sizeof (mem_cpointer_t)) + (max_property_count >> 3))
/**
* Number of items in the stepping table.
*/
#define ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS 8
/**
* Stepping values for searching items in the hashmap.
*/
static const uint32_t ecma_property_hashmap_steps[ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS] =
{
3, 5, 7, 11, 13, 17, 19, 23
};
/**
* Get the value of a bit in a bitmap.
*/
#define ECMA_PROPERTY_HASHMAP_GET_BIT(byte_p, index) \
((byte_p)[(index) >> 3] & (1 << ((index) & 0x7)))
/**
* Clear the value of a bit in a bitmap.
*/
#define ECMA_PROPERTY_HASHMAP_CLEAR_BIT(byte_p, index) \
((byte_p)[(index) >> 3] = (uint8_t) ((byte_p)[(index) >> 3] & ~(1 << ((index) & 0x7))))
/**
* Set the value of a bit in a bitmap.
*/
#define ECMA_PROPERTY_HASHMAP_SET_BIT(byte_p, index) \
((byte_p)[(index) >> 3] = (uint8_t) ((byte_p)[(index) >> 3] | (1 << ((index) & 0x7))))
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
/**
* Create a new property hashmap for the object.
* The object must not have a property hashmap.
*/
void
ecma_property_hashmap_create (ecma_object_t *object_p) /**< object */
{
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
JERRY_ASSERT (ecma_get_property_list (object_p) != NULL);
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (ecma_get_property_list (object_p)));
uint32_t named_property_count = 0;
ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p);
while (prop_iter_p != NULL)
{
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
{
ecma_property_types_t type = ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + i);
if (type == ECMA_PROPERTY_TYPE_NAMEDDATA || type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
{
named_property_count++;
}
}
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
/* The max_property_count must be power of 2. */
uint32_t max_property_count = ECMA_PROPERTY_HASMAP_MINIMUM_SIZE;
/* At least 1/3 items must be NULL. */
while (max_property_count < (named_property_count + (named_property_count >> 1)))
{
max_property_count <<= 1;
}
size_t total_size = ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE (max_property_count);
ecma_property_hashmap_t *hashmap_p = (ecma_property_hashmap_t *) mem_heap_alloc_block (total_size);
memset (hashmap_p, 0, total_size);
hashmap_p->header.types[0].type_and_flags = ECMA_PROPERTY_TYPE_HASHMAP;
hashmap_p->header.next_property_cp = object_p->property_list_or_bound_object_cp;
hashmap_p->max_property_count = max_property_count;
hashmap_p->null_count = max_property_count - named_property_count;
mem_cpointer_t *pair_list_p = (mem_cpointer_t *) (hashmap_p + 1);
uint8_t *bits_p = (uint8_t *) (pair_list_p + max_property_count);
uint32_t mask = max_property_count - 1;
uint8_t shift_counter = 0;
if (max_property_count <= (1u << LIT_STRING_HASH_BITS))
{
hashmap_p->header.types[1].type_and_flags = 0;
}
else
{
while (max_property_count > (1u << LIT_STRING_HASH_BITS))
{
shift_counter++;
max_property_count >>= 1;
}
}
hashmap_p->header.types[1].type_and_flags = shift_counter;
prop_iter_p = ecma_get_property_list (object_p);
ECMA_SET_POINTER (object_p->property_list_or_bound_object_cp, hashmap_p);
while (prop_iter_p != NULL)
{
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
{
ecma_property_types_t type = ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + i);
if (!(type == ECMA_PROPERTY_TYPE_NAMEDDATA || type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR))
{
continue;
}
ecma_property_pair_t *property_pair_p = (ecma_property_pair_t *) prop_iter_p;
ecma_string_t *name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_pair_p->names_cp[i]);
uint32_t entry_index = name_p->hash;
uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
if (mask < (1u << LIT_STRING_HASH_BITS))
{
entry_index &= mask;
}
else
{
entry_index <<= shift_counter;
JERRY_ASSERT (entry_index <= mask);
}
#ifndef JERRY_NDEBUG
/* Because max_property_count (power of 2) and step (a prime
* number) are relative primes, all entries of the hasmap are
* visited exactly once before the start entry index is reached
* again. Furthermore because at least one NULL is present in
* the hashmap, the while loop must be terminated before the
* the starting index is reached again. */
uint32_t start_entry_index = entry_index;
#endif /* !JERRY_NDEBUG */
while (pair_list_p[entry_index] != ECMA_NULL_POINTER)
{
entry_index = (entry_index + step) & mask;
#ifndef JERRY_NDEBUG
JERRY_ASSERT (entry_index != start_entry_index);
#endif /* !JERRY_NDEBUG */
}
ECMA_SET_POINTER (pair_list_p[entry_index], property_pair_p);
if (i != 0)
{
ECMA_PROPERTY_HASHMAP_SET_BIT (bits_p, entry_index);
}
}
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
#else /* CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
(void) object_p;
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
} /* ecma_property_hashmap_create */
/**
* Free the hashmap of the object.
* The object must have a property hashmap.
*/
void
ecma_property_hashmap_free (ecma_object_t *object_p) /**< object */
{
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
/* Property hash must be exists and must be the first property. */
ecma_property_header_t *property_p = ecma_get_property_list (object_p);
JERRY_ASSERT (property_p != NULL
&& ECMA_PROPERTY_GET_TYPE (property_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP);
ecma_property_hashmap_t *hashmap_p = (ecma_property_hashmap_t *) property_p;
object_p->property_list_or_bound_object_cp = property_p->next_property_cp;
mem_heap_free_block (hashmap_p,
ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE (hashmap_p->max_property_count));
#else /* CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
(void) object_p;
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
} /* ecma_property_hashmap_free */
/**
* Insert named property into the hashmap.
*/
void
ecma_property_hashmap_insert (ecma_object_t *object_p, /**< object */
ecma_string_t *name_p, /**< name of the property */
ecma_property_pair_t *property_pair_p, /**< property pair */
int property_index) /**< property index in the pair (0 or 1) */
{
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
ecma_property_hashmap_t *hashmap_p = ECMA_GET_NON_NULL_POINTER (ecma_property_hashmap_t,
object_p->property_list_or_bound_object_cp);
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (hashmap_p->header.types + 0) == ECMA_PROPERTY_TYPE_HASHMAP);
/* The NULLs are reduced below 1/8 of the hashmap. */
if (hashmap_p->null_count < (hashmap_p->max_property_count >> 3))
{
ecma_property_hashmap_free (object_p);
ecma_property_hashmap_create (object_p);
return;
}
JERRY_ASSERT (property_index < ECMA_PROPERTY_PAIR_ITEM_COUNT);
uint32_t entry_index = name_p->hash;
uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
uint32_t mask = hashmap_p->max_property_count - 1;
if (mask < (1u << LIT_STRING_HASH_BITS))
{
entry_index &= mask;
}
else
{
entry_index <<= hashmap_p->header.types[1].type_and_flags;
}
#ifndef JERRY_NDEBUG
/* See the comment for this variable in ecma_property_hashmap_create. */
uint32_t start_entry_index = entry_index;
#endif /* !JERRY_NDEBUG */
mem_cpointer_t *pair_list_p = (mem_cpointer_t *) (hashmap_p + 1);
while (pair_list_p[entry_index] != ECMA_NULL_POINTER)
{
entry_index = (entry_index + step) & mask;
#ifndef JERRY_NDEBUG
JERRY_ASSERT (entry_index != start_entry_index);
#endif /* !JERRY_NDEBUG */
}
ECMA_SET_POINTER (pair_list_p[entry_index], property_pair_p);
uint8_t *bits_p = (uint8_t *) (pair_list_p + hashmap_p->max_property_count);
bits_p += (entry_index >> 3);
mask = (uint32_t) (1 << (entry_index & 0x7));
if (!(*bits_p & mask))
{
/* Deleted entries also has ECMA_NULL_POINTER
* value, but they are not NULL values. */
hashmap_p->null_count--;
JERRY_ASSERT (hashmap_p->null_count > 0);
}
if (property_index == 0)
{
*bits_p = (uint8_t) ((*bits_p) & ~mask);
}
else
{
*bits_p = (uint8_t) ((*bits_p) | mask);
}
#else /* CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
(void) object_p;
(void) name_p;
(void) property_pair_p;
(void) property_index;
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
} /* ecma_property_hashmap_insert */
/**
* Delete named property from the hashmap.
*/
void
ecma_property_hashmap_delete (ecma_object_t *object_p, /**< object */
ecma_string_t *name_p, /**< name of the property */
ecma_property_t *property_p) /**< property */
{
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
ecma_property_hashmap_t *hashmap_p = ECMA_GET_NON_NULL_POINTER (ecma_property_hashmap_t,
object_p->property_list_or_bound_object_cp);
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (hashmap_p->header.types + 0) == ECMA_PROPERTY_TYPE_HASHMAP);
uint32_t entry_index = name_p->hash;
uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
uint32_t mask = hashmap_p->max_property_count - 1;
mem_cpointer_t *pair_list_p = (mem_cpointer_t *) (hashmap_p + 1);
uint8_t *bits_p = (uint8_t *) (pair_list_p + hashmap_p->max_property_count);
if (mask < (1u << LIT_STRING_HASH_BITS))
{
entry_index &= mask;
}
else
{
entry_index <<= hashmap_p->header.types[1].type_and_flags;
JERRY_ASSERT (entry_index <= mask);
}
#ifndef JERRY_NDEBUG
/* See the comment for this variable in ecma_property_hashmap_create. */
uint32_t start_entry_index = entry_index;
#endif /* !JERRY_NDEBUG */
while (true)
{
if (pair_list_p[entry_index] != ECMA_NULL_POINTER)
{
size_t offset = 0;
if (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
{
offset = 1;
}
ecma_property_pair_t *property_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_property_pair_t,
pair_list_p[entry_index]);
if ((property_pair_p->header.types + offset) == property_p)
{
JERRY_ASSERT (ecma_compare_ecma_strings (ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_pair_p->names_cp[offset]),
name_p));
pair_list_p[entry_index] = ECMA_NULL_POINTER;
ECMA_PROPERTY_HASHMAP_SET_BIT (bits_p, entry_index);
return;
}
}
else
{
/* Must be a deleted entry. */
JERRY_ASSERT (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index));
}
entry_index = (entry_index + step) & mask;
#ifndef JERRY_NDEBUG
JERRY_ASSERT (entry_index != start_entry_index);
#endif /* !JERRY_NDEBUG */
}
#else /* CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
(void) object_p;
(void) name_p;
(void) property_p;
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
} /* ecma_property_hashmap_delete */
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
/**
* Find a named property.
*
* @return pointer to the property if found or NULL otherwise
*/
ecma_property_t *
ecma_property_hashmap_find (ecma_property_hashmap_t *hashmap_p, /**< hashmap */
ecma_string_t *name_p) /**< property name */
{
#ifndef JERRY_NDEBUG
/* A sanity check in debug mode: a named property must be present
* in both the property hashmap and in the property chain, or missing
* from both data collection. The following code checks the property
* chain, and sets the property_found variable. */
bool property_found = false;
ecma_property_header_t *prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
hashmap_p->header.next_property_cp);
while (prop_iter_p != NULL && !property_found)
{
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
{
if (prop_pair_p->names_cp[i] != ECMA_NULL_POINTER)
{
ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
prop_pair_p->names_cp[i]);
if (ecma_compare_ecma_strings (name_p, property_name_p))
{
property_found = true;
break;
}
}
}
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
#endif /* !JERRY_NDEBUG */
uint32_t entry_index = name_p->hash;
uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)];
uint32_t mask = hashmap_p->max_property_count - 1;
mem_cpointer_t *pair_list_p = (mem_cpointer_t *) (hashmap_p + 1);
uint8_t *bits_p = (uint8_t *) (pair_list_p + hashmap_p->max_property_count);
if (mask < (1u << LIT_STRING_HASH_BITS))
{
entry_index &= mask;
}
else
{
entry_index <<= hashmap_p->header.types[1].type_and_flags;
JERRY_ASSERT (entry_index <= mask);
}
#ifndef JERRY_NDEBUG
/* See the comment for this variable in ecma_property_hashmap_create. */
uint32_t start_entry_index = entry_index;
#endif /* !JERRY_NDEBUG */
while (true)
{
if (pair_list_p[entry_index] != ECMA_NULL_POINTER)
{
size_t offset = 0;
if (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
{
offset = 1;
}
ecma_property_pair_t *property_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_property_pair_t,
pair_list_p[entry_index]);
ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
property_pair_p->names_cp[offset]);
if (ecma_compare_ecma_strings (name_p, property_name_p))
{
#ifndef JERRY_NDEBUG
JERRY_ASSERT (property_found);
#endif /* !JERRY_NDEBUG */
return property_pair_p->header.types + offset;
}
}
else
{
if (!ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index))
{
#ifndef JERRY_NDEBUG
JERRY_ASSERT (!property_found);
#endif /* !JERRY_NDEBUG */
return NULL;
}
/* Otherwise it is a deleted entry. */
}
entry_index = (entry_index + step) & mask;
#ifndef JERRY_NDEBUG
JERRY_ASSERT (entry_index != start_entry_index);
#endif /* !JERRY_NDEBUG */
}
} /* ecma_property_hashmap_find */
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
/**
* @}
* @}
*/

View File

@ -0,0 +1,70 @@
/* Copyright 2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* 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_PROPERTY_HASHMAP_H
#define ECMA_PROPERTY_HASHMAP_H
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmapropertyhashmap Property hashmap
* @{
*/
/**
* Recommended minimum number of items in a property cache.
*/
#define ECMA_PROPERTY_HASMAP_MINIMUM_SIZE 32
/**
* Property hash.
*/
typedef struct
{
ecma_property_header_t header; /**< header of the property */
uint32_t max_property_count; /**< maximum property count (power of 2) */
uint32_t null_count; /**< number of NULLs in the map */
/*
* The hash is followed by max_property_count ecma_cpointer_t
* compressed pointers and (max_property_count + 7) / 8 bytes
* which stores a flag for each compressed pointer.
*
* If the compressed pointer is equal to ECMA_NULL_POINTER
* - flag is cleared if the entry is NULL
* - flag is set if the entry is deleted
*
* If the compressed pointer is not equal to ECMA_NULL_POINTER
* - flag is cleared if the first entry of a property pair is referenced
* - flag is set if the second entry of a property pair is referenced
*/
} ecma_property_hashmap_t;
extern void ecma_property_hashmap_create (ecma_object_t *);
extern void ecma_property_hashmap_free (ecma_object_t *);
extern void ecma_property_hashmap_insert (ecma_object_t *, ecma_string_t *, ecma_property_pair_t *, int);
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 *);
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
/**
* @}
* @}
*/
#endif /* !ECMA_PROPERTY_HASHMAP_H */

View File

@ -626,6 +626,13 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */
ecma_property_header_t *prop_iter_p = ecma_get_property_list (prototype_chain_iter_p);
if (prop_iter_p != NULL
&& ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP)
{
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
prop_iter_p->next_property_cp);
}
while (prop_iter_p != NULL)
{
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));