Skip to content

More gc-friendly property hashmap allocation. #1195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions jerry-core/ecma/base/ecma-gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */
* Run garbage collection
*/
void
ecma_gc_run (void)
ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */
{
ecma_gc_new_objects_since_last_gc = 0;

Expand Down Expand Up @@ -577,6 +577,26 @@ ecma_gc_run (void)
ecma_gc_sweep (obj_iter_p);
}

if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH)
{
/* Remove the property hashmap of BLACK objects */
for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK], *obj_next_p;
obj_iter_p != NULL;
obj_iter_p = obj_next_p)
{
obj_next_p = ecma_gc_get_object_next (obj_iter_p);

JERRY_ASSERT (ecma_gc_is_object_visited (obj_iter_p));

ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_iter_p);
if (prop_iter_p != NULL
&& ECMA_PROPERTY_GET_TYPE (prop_iter_p->types + 0) == ECMA_PROPERTY_TYPE_HASHMAP)
{
ecma_property_hashmap_free (obj_iter_p);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need the newline above.

}

/* Unmarking all objects */
ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY] = ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK];
ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK] = NULL;
Expand All @@ -603,15 +623,15 @@ ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< sever
*/
if (ecma_gc_new_objects_since_last_gc * CONFIG_ECMA_GC_NEW_OBJECTS_SHARE_TO_START_GC > ecma_gc_objects_number)
{
ecma_gc_run ();
ecma_gc_run (severity);
}
}
else
{
JERRY_ASSERT (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH);

/* Freeing as much memory as we currently can */
ecma_gc_run ();
ecma_gc_run (severity);
}
} /* ecma_free_unused_memory */

Expand Down
2 changes: 1 addition & 1 deletion jerry-core/ecma/base/ecma-gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ extern void ecma_gc_init (void);
extern void ecma_init_gc_info (ecma_object_t *);
extern void ecma_ref_object (ecma_object_t *);
extern void ecma_deref_object (ecma_object_t *);
extern void ecma_gc_run (void);
extern void ecma_gc_run (jmem_free_unused_memory_severity_t);
extern void ecma_free_unused_memory (jmem_free_unused_memory_severity_t);

/**
Expand Down
2 changes: 1 addition & 1 deletion jerry-core/ecma/base/ecma-init-finalize.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ ecma_finalize (void)

ecma_finalize_environment ();
ecma_finalize_builtins ();
ecma_gc_run ();
ecma_gc_run (JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW);
ecma_finalize_lit_storage ();
} /* ecma_finalize */

Expand Down
8 changes: 7 additions & 1 deletion jerry-core/ecma/base/ecma-property-hashmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,13 @@ ecma_property_hashmap_create (ecma_object_t *object_p) /**< object */

size_t total_size = ECMA_PROPERTY_HASHMAP_GET_TOTAL_SIZE (max_property_count);

ecma_property_hashmap_t *hashmap_p = (ecma_property_hashmap_t *) jmem_heap_alloc_block (total_size);
ecma_property_hashmap_t *hashmap_p = (ecma_property_hashmap_t *) jmem_heap_alloc_block_null_on_error (total_size);

if (hashmap_p == NULL)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we could think about a strategy what should happen if we are on low-memory conditions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style: add a newline before the 'if'.

{
return;
}

memset (hashmap_p, 0, total_size);

hashmap_p->header.types[0].type_and_flags = ECMA_PROPERTY_TYPE_HASHMAP;
Expand Down
2 changes: 1 addition & 1 deletion jerry-core/jerry.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ jerry_gc (void)
{
jerry_assert_api_available ();

ecma_gc_run ();
ecma_gc_run (JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW);
} /* jerry_gc */

/**
Expand Down
52 changes: 47 additions & 5 deletions jerry-core/jmem/jmem-heap.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,12 +321,17 @@ void *jmem_heap_alloc_block_internal (const size_t size)
* Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory.
*
* Note:
* if after running the callbacks, there is still not enough memory, engine is terminated with ERR_OUT_OF_MEMORY.
* if there is still not enough memory after running the callbacks
* - NULL value will be returned if parmeter 'ret_null_on_error' is true
* - the engine will terminate with ERR_OUT_OF_MEMORY if 'ret_null_on_error' is false
*
* @return pointer to allocated memory block
* @return NULL, if the required memory size is 0
* also NULL, if 'ret_null_on_error' is true and the allocation fails because of there is not enough memory
*/
void * __attribute__((hot))
jmem_heap_alloc_block (const size_t size)
static void *
jmem_heap_gc_and_alloc_block (const size_t size, /**< required memory size */
bool ret_null_on_error) /**< indicates whether return null or terminate
with ERR_OUT_OF_MEMORY on out of memory */
{
if (unlikely (size == 0))
{
Expand Down Expand Up @@ -369,9 +374,46 @@ jmem_heap_alloc_block (const size_t size)

JERRY_ASSERT (data_space_p == NULL);

jerry_fatal (ERR_OUT_OF_MEMORY);
if (!ret_null_on_error)
{
jerry_fatal (ERR_OUT_OF_MEMORY);
}

return data_space_p;
} /* jmem_heap_gc_and_alloc_block */

/**
* Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory.
*
* Note:
* If there is still not enough memory after running the callbacks, then the engine will be
* terminated with ERR_OUT_OF_MEMORY.
*
* @return NULL, if the required memory is 0
* pointer to allocated memory block, otherwise
*/
void * __attribute__((hot)) __attr_always_inline___
jmem_heap_alloc_block (const size_t size) /**< required memory size */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would implement this a bit differently. I would add a bool parameter to jmem_heap_gc_and_alloc_block to tell whether it should return with NULL or error, and make these functions a one-liner always inline functionsa, and just set that bool parameter.

{
return jmem_heap_gc_and_alloc_block (size, false);
} /* jmem_heap_alloc_block */

/**
* Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory.
*
* Note:
* If there is still not enough memory after running the callbacks, NULL will be returned.
*
* @return NULL, if the required memory size is 0
* also NULL, if the allocation has failed
* pointer to the allocated memory block, otherwise
*/
void * __attribute__((hot)) __attr_always_inline___
jmem_heap_alloc_block_null_on_error (const size_t size) /**< required memory size */
{
return jmem_heap_gc_and_alloc_block (size, true);
} /* jmem_heap_alloc_block_null_on_error */

/**
* Allocate block and store block size.
*
Expand Down
1 change: 1 addition & 0 deletions jerry-core/jmem/jmem-heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
extern void jmem_heap_init (void);
extern void jmem_heap_finalize (void);
extern void *jmem_heap_alloc_block (const size_t);
extern void *jmem_heap_alloc_block_null_on_error (const size_t);
extern void jmem_heap_free_block (void *, const size_t);
extern void *jmem_heap_alloc_block_store_size (size_t);
extern void jmem_heap_free_block_size_stored (void *);
Expand Down