Add info to external pointer free callback. (#4642)
Furthermore reduce memory consumption when only one external pointer is assigned to an object. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
@@ -1175,37 +1175,54 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
|
||||
* Free the native handle/pointer by calling its free callback.
|
||||
*/
|
||||
static void
|
||||
ecma_gc_free_native_pointer (ecma_value_t value) /**< property value */
|
||||
ecma_gc_free_native_pointer (ecma_property_t property, /**< property descriptor */
|
||||
ecma_value_t value) /**< property value */
|
||||
{
|
||||
if (JERRY_LIKELY (property & ECMA_PROPERTY_FLAG_SINGLE_EXTERNAL))
|
||||
{
|
||||
JERRY_ASSERT (value != JMEM_CP_NULL);
|
||||
|
||||
ecma_native_pointer_t *native_pointer_p;
|
||||
native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, value);
|
||||
|
||||
jerry_object_native_free_callback_t free_cb = native_pointer_p->info_p->free_cb;
|
||||
|
||||
if (free_cb != NULL)
|
||||
{
|
||||
free_cb (native_pointer_p->native_p, native_pointer_p->info_p);
|
||||
}
|
||||
|
||||
jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == JMEM_CP_NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ecma_native_pointer_t *native_pointer_p;
|
||||
|
||||
native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, value);
|
||||
JERRY_ASSERT (native_pointer_p != NULL);
|
||||
ecma_native_pointer_chain_t *item_p;
|
||||
item_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_chain_t, value);
|
||||
|
||||
do
|
||||
{
|
||||
if (native_pointer_p->info_p != NULL)
|
||||
if (item_p->data.info_p != NULL)
|
||||
{
|
||||
ecma_object_native_free_callback_t free_cb = native_pointer_p->info_p->free_cb;
|
||||
jerry_object_native_free_callback_t free_cb = item_p->data.info_p->free_cb;
|
||||
|
||||
if (free_cb != NULL)
|
||||
{
|
||||
free_cb (native_pointer_p->data_p);
|
||||
free_cb (item_p->data.native_p, item_p->data.info_p);
|
||||
}
|
||||
}
|
||||
|
||||
ecma_native_pointer_t *next_p = native_pointer_p->next_p;
|
||||
ecma_native_pointer_chain_t *next_p = item_p->next_p;
|
||||
|
||||
jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t));
|
||||
jmem_heap_free_block (item_p, sizeof (ecma_native_pointer_chain_t));
|
||||
|
||||
native_pointer_p = next_p;
|
||||
item_p = next_p;
|
||||
}
|
||||
while (native_pointer_p != NULL);
|
||||
while (item_p != NULL);
|
||||
} /* ecma_gc_free_native_pointer */
|
||||
|
||||
/**
|
||||
@@ -1518,7 +1535,7 @@ ecma_gc_free_property (ecma_object_t *object_p, /**< object */
|
||||
default:
|
||||
{
|
||||
JERRY_ASSERT (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
|
||||
ecma_gc_free_native_pointer (value);
|
||||
ecma_gc_free_native_pointer (property, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,27 +299,22 @@ typedef ecma_value_t (*ecma_native_handler_t) (const struct jerry_call_info_t *c
|
||||
const uint32_t args_count);
|
||||
|
||||
/**
|
||||
* Native free callback of an object.
|
||||
*/
|
||||
typedef void (*ecma_object_native_free_callback_t) (void *native_p);
|
||||
|
||||
/**
|
||||
* Type information of a native pointer.
|
||||
* Representation of native pointer data.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ecma_object_native_free_callback_t free_cb; /**< the free callback of the native pointer */
|
||||
} ecma_object_native_info_t;
|
||||
void *native_p; /**< points to the data of the object */
|
||||
jerry_object_native_info_t *info_p; /**< native info */
|
||||
} ecma_native_pointer_t;
|
||||
|
||||
/**
|
||||
* Representation for native pointer data.
|
||||
* Representation of native pointer data chain.
|
||||
*/
|
||||
typedef struct ecma_native_pointer_t
|
||||
typedef struct ecma_native_pointer_chain_t
|
||||
{
|
||||
void *data_p; /**< points to the data of the object */
|
||||
ecma_object_native_info_t *info_p; /**< native info */
|
||||
struct ecma_native_pointer_t *next_p; /**< points to the next ecma_native_pointer_t element */
|
||||
} ecma_native_pointer_t;
|
||||
ecma_native_pointer_t data; /**< pointer data */
|
||||
struct ecma_native_pointer_chain_t *next_p; /**< next in the list */
|
||||
} ecma_native_pointer_chain_t;
|
||||
|
||||
/**
|
||||
* Option bits for ecma_parse_options_t.
|
||||
@@ -415,7 +410,7 @@ typedef enum
|
||||
ECMA_PROPERTY_FLAG_CONFIGURABLE = (1u << 0), /**< property is configurable */
|
||||
ECMA_PROPERTY_FLAG_ENUMERABLE = (1u << 1), /**< property is enumerable */
|
||||
ECMA_PROPERTY_FLAG_WRITABLE = (1u << 2), /**< property is writable */
|
||||
|
||||
ECMA_PROPERTY_FLAG_SINGLE_EXTERNAL = (1u << 2), /**< only one external pointer is assigned to this object */
|
||||
ECMA_PROPERTY_FLAG_DELETED = (1u << 3), /**< property is deleted */
|
||||
ECMA_FAST_ARRAY_FLAG = (1u << 3), /**< array is fast array */
|
||||
ECMA_PROPERTY_FLAG_LCACHED = (1u << 4), /**< property is lcached */
|
||||
@@ -1849,7 +1844,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
ecma_long_string_t header;
|
||||
ecma_object_native_free_callback_t free_cb; /**< free callback */
|
||||
jerry_value_free_callback_t free_cb; /**< free callback */
|
||||
} ecma_external_string_t;
|
||||
|
||||
/**
|
||||
@@ -2101,7 +2096,7 @@ typedef struct
|
||||
{
|
||||
ecma_extended_object_t extended_object; /**< extended object part */
|
||||
void *buffer_p; /**< external buffer pointer */
|
||||
ecma_object_native_free_callback_t free_cb; /**< the free callback for the above buffer pointer */
|
||||
jerry_value_free_callback_t free_cb; /**< the free callback for the above buffer pointer */
|
||||
} ecma_arraybuffer_external_info;
|
||||
|
||||
/**
|
||||
|
||||
@@ -56,8 +56,35 @@ ecma_create_native_pointer_property (ecma_object_t *obj_p, /**< object to create
|
||||
ecma_property_value_t *value_p;
|
||||
ECMA_CREATE_INTERNAL_PROPERTY (obj_p, name_p, property_p, value_p);
|
||||
|
||||
native_pointer_p = jmem_heap_alloc_block (sizeof (ecma_native_pointer_t));
|
||||
native_pointer_p = (ecma_native_pointer_t *) jmem_heap_alloc_block (sizeof (ecma_native_pointer_t));
|
||||
ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, native_pointer_p);
|
||||
|
||||
*property_p |= ECMA_PROPERTY_FLAG_SINGLE_EXTERNAL;
|
||||
}
|
||||
else if (*property_p & ECMA_PROPERTY_FLAG_SINGLE_EXTERNAL)
|
||||
{
|
||||
ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
|
||||
|
||||
native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, value_p->value);
|
||||
|
||||
if (native_pointer_p->info_p == info_p)
|
||||
{
|
||||
native_pointer_p->native_p = native_p;
|
||||
return false;
|
||||
}
|
||||
|
||||
ecma_native_pointer_chain_t *item_p;
|
||||
item_p = (ecma_native_pointer_chain_t *) jmem_heap_alloc_block (sizeof (ecma_native_pointer_chain_t));
|
||||
item_p->data = *native_pointer_p;
|
||||
|
||||
jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t));
|
||||
|
||||
item_p->next_p = (ecma_native_pointer_chain_t *) jmem_heap_alloc_block (sizeof (ecma_native_pointer_chain_t));
|
||||
item_p->next_p->next_p = NULL;
|
||||
|
||||
native_pointer_p = &item_p->next_p->data;
|
||||
*property_p &= (ecma_property_t) ~ECMA_PROPERTY_FLAG_SINGLE_EXTERNAL;
|
||||
ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, item_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -65,42 +92,48 @@ ecma_create_native_pointer_property (ecma_object_t *obj_p, /**< object to create
|
||||
|
||||
if (value_p->value == JMEM_CP_NULL)
|
||||
{
|
||||
native_pointer_p = jmem_heap_alloc_block (sizeof (ecma_native_pointer_t));
|
||||
native_pointer_p = (ecma_native_pointer_t *) jmem_heap_alloc_block (sizeof (ecma_native_pointer_t));
|
||||
ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, native_pointer_p);
|
||||
|
||||
*property_p |= ECMA_PROPERTY_FLAG_SINGLE_EXTERNAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ecma_native_pointer_t *iter_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, value_p->value);
|
||||
ecma_native_pointer_chain_t *item_p;
|
||||
item_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_chain_t, value_p->value);
|
||||
|
||||
/* There should be at least 1 native pointer in the chain */
|
||||
JERRY_ASSERT (iter_p != NULL);
|
||||
/* There should be at least 2 native pointers in the chain */
|
||||
JERRY_ASSERT (item_p != NULL && item_p->next_p != NULL);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (iter_p->info_p == info_p)
|
||||
if (item_p->data.info_p == info_p)
|
||||
{
|
||||
/* The native info already exists -> update the corresponding data */
|
||||
iter_p->data_p = native_p;
|
||||
item_p->data.native_p = native_p;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iter_p->next_p == NULL)
|
||||
if (item_p->next_p == NULL)
|
||||
{
|
||||
/* The native info does not exist -> append a new element to the chain */
|
||||
break;
|
||||
}
|
||||
|
||||
iter_p = iter_p->next_p;
|
||||
item_p = item_p->next_p;
|
||||
}
|
||||
|
||||
native_pointer_p = jmem_heap_alloc_block (sizeof (ecma_native_pointer_t));
|
||||
iter_p->next_p = native_pointer_p;
|
||||
ecma_native_pointer_chain_t *new_item_p;
|
||||
|
||||
new_item_p = (ecma_native_pointer_chain_t *) jmem_heap_alloc_block (sizeof (ecma_native_pointer_chain_t));
|
||||
item_p->next_p = new_item_p;
|
||||
|
||||
native_pointer_p = &new_item_p->data;
|
||||
}
|
||||
}
|
||||
|
||||
native_pointer_p->data_p = native_p;
|
||||
native_pointer_p->native_p = native_p;
|
||||
native_pointer_p->info_p = info_p;
|
||||
native_pointer_p->next_p = NULL;
|
||||
|
||||
return is_new;
|
||||
} /* ecma_create_native_pointer_property */
|
||||
@@ -135,25 +168,40 @@ ecma_get_native_pointer_value (ecma_object_t *obj_p, /**< object to get property
|
||||
|
||||
ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
|
||||
|
||||
if (value_p->value == JMEM_CP_NULL)
|
||||
if (JERRY_LIKELY (*property_p & ECMA_PROPERTY_FLAG_SINGLE_EXTERNAL))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
ecma_native_pointer_t *native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t,
|
||||
value_p->value);
|
||||
|
||||
ecma_native_pointer_t *native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t,
|
||||
value_p->value);
|
||||
JERRY_ASSERT (native_pointer_p != NULL);
|
||||
|
||||
do
|
||||
{
|
||||
if (native_pointer_p->info_p == info_p)
|
||||
{
|
||||
return native_pointer_p;
|
||||
}
|
||||
|
||||
native_pointer_p = native_pointer_p->next_p;
|
||||
return NULL;
|
||||
}
|
||||
while (native_pointer_p != NULL);
|
||||
|
||||
if (value_p->value == JMEM_CP_NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ecma_native_pointer_chain_t *item_p;
|
||||
item_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_chain_t, value_p->value);
|
||||
|
||||
/* There should be at least 2 native pointers in the chain */
|
||||
JERRY_ASSERT (item_p != NULL && item_p->next_p != NULL);
|
||||
|
||||
do
|
||||
{
|
||||
if (item_p->data.info_p == info_p)
|
||||
{
|
||||
return &item_p->data;
|
||||
}
|
||||
|
||||
item_p = item_p->next_p;
|
||||
}
|
||||
while (item_p != NULL);
|
||||
|
||||
return NULL;
|
||||
} /* ecma_get_native_pointer_value */
|
||||
@@ -188,40 +236,75 @@ ecma_delete_native_pointer_property (ecma_object_t *obj_p, /**< object to delete
|
||||
|
||||
ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
|
||||
|
||||
if (JERRY_LIKELY (*property_p & ECMA_PROPERTY_FLAG_SINGLE_EXTERNAL))
|
||||
{
|
||||
ecma_native_pointer_t *native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t,
|
||||
value_p->value);
|
||||
|
||||
if (native_pointer_p->info_p != info_p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value_p->value = JMEM_CP_NULL;
|
||||
*property_p &= (ecma_property_t) ~ECMA_PROPERTY_FLAG_SINGLE_EXTERNAL;
|
||||
jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value_p->value == JMEM_CP_NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ecma_native_pointer_t *native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t,
|
||||
value_p->value);
|
||||
JERRY_ASSERT (native_pointer_p != NULL);
|
||||
ecma_native_pointer_chain_t *first_p;
|
||||
first_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_chain_t, value_p->value);
|
||||
|
||||
ecma_native_pointer_t *prev_p = NULL;
|
||||
/* There should be at least 2 native pointers in the chain */
|
||||
JERRY_ASSERT (first_p != NULL && first_p->next_p != NULL);
|
||||
|
||||
ecma_native_pointer_chain_t *item_p = first_p;
|
||||
ecma_native_pointer_chain_t *prev_p = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
if (native_pointer_p->info_p == info_p)
|
||||
if (item_p->data.info_p == info_p)
|
||||
{
|
||||
if (prev_p == NULL)
|
||||
{
|
||||
/* The first element is deleted from the chain: change the property value. */
|
||||
ECMA_SET_INTERNAL_VALUE_ANY_POINTER (value_p->value, native_pointer_p->next_p);
|
||||
first_p = item_p->next_p;
|
||||
ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, first_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A non-first element is deleted from the chain: update the previous pointer. */
|
||||
prev_p->next_p = native_pointer_p->next_p;
|
||||
prev_p->next_p = item_p->next_p;
|
||||
}
|
||||
|
||||
jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t));
|
||||
jmem_heap_free_block (item_p, sizeof (ecma_native_pointer_chain_t));
|
||||
|
||||
if (first_p->next_p != NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Only one item remained. */
|
||||
ecma_native_pointer_t *native_pointer_p;
|
||||
native_pointer_p = (ecma_native_pointer_t *) jmem_heap_alloc_block (sizeof (ecma_native_pointer_t));
|
||||
*native_pointer_p = first_p->data;
|
||||
|
||||
jmem_heap_free_block (first_p, sizeof (ecma_native_pointer_chain_t));
|
||||
|
||||
ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, native_pointer_p);
|
||||
*property_p |= ECMA_PROPERTY_FLAG_SINGLE_EXTERNAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
prev_p = native_pointer_p;
|
||||
native_pointer_p = native_pointer_p->next_p;
|
||||
prev_p = item_p;
|
||||
item_p = item_p->next_p;
|
||||
}
|
||||
while (native_pointer_p != NULL);
|
||||
while (item_p != NULL);
|
||||
|
||||
return false;
|
||||
} /* ecma_delete_native_pointer_property */
|
||||
|
||||
@@ -455,7 +455,7 @@ ecma_new_ecma_string_from_utf8_converted_to_cesu8 (const lit_utf8_byte_t *string
|
||||
ecma_string_t *
|
||||
ecma_new_ecma_external_string_from_cesu8 (const lit_utf8_byte_t *string_p, /**< cesu-8 string */
|
||||
lit_utf8_size_t string_size, /**< string size */
|
||||
ecma_object_native_free_callback_t free_cb) /**< free callback */
|
||||
jerry_value_free_callback_t free_cb) /**< free callback */
|
||||
{
|
||||
JERRY_ASSERT (string_p != NULL || string_size == 0);
|
||||
JERRY_ASSERT (lit_is_valid_cesu8_string (string_p, string_size));
|
||||
|
||||
@@ -303,7 +303,7 @@ ecma_string_t *ecma_new_ecma_string_from_utf8 (const lit_utf8_byte_t *string_p,
|
||||
ecma_string_t *ecma_new_ecma_string_from_utf8_converted_to_cesu8 (const lit_utf8_byte_t *string_p,
|
||||
lit_utf8_size_t string_size);
|
||||
ecma_string_t *ecma_new_ecma_external_string_from_cesu8 (const lit_utf8_byte_t *string_p, lit_utf8_size_t string_size,
|
||||
ecma_object_native_free_callback_t free_cb);
|
||||
jerry_value_free_callback_t free_cb);
|
||||
ecma_string_t *ecma_new_ecma_string_from_code_unit (ecma_char_t code_unit);
|
||||
#if JERRY_ESNEXT
|
||||
ecma_string_t *ecma_new_ecma_string_from_code_units (ecma_char_t first_code_unit, ecma_char_t second_code_unit);
|
||||
|
||||
Reference in New Issue
Block a user