Revise internal array creation operations (#4291)
JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
This commit is contained in:
@@ -66,8 +66,8 @@
|
||||
*
|
||||
* @return pointer to the constructed array object
|
||||
*/
|
||||
ecma_object_t *
|
||||
ecma_op_new_array_object (uint32_t length) /**< length of the new array */
|
||||
static ecma_object_t *
|
||||
ecma_op_alloc_array_object (uint32_t length) /**< length of the new array */
|
||||
{
|
||||
#if ENABLED (JERRY_BUILTIN_ARRAY)
|
||||
ecma_object_t *array_prototype_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE);
|
||||
@@ -91,7 +91,7 @@ ecma_op_new_array_object (uint32_t length) /**< length of the new array */
|
||||
ext_obj_p->u.array.u.length_prop = ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_TYPE_VIRTUAL;
|
||||
|
||||
return object_p;
|
||||
} /* ecma_op_new_array_object */
|
||||
} /* ecma_op_alloc_array_object */
|
||||
|
||||
/**
|
||||
* Check whether the given object is fast-access mode array
|
||||
@@ -121,43 +121,184 @@ ecma_op_array_is_fast_array (ecma_extended_object_t *array_p) /**< ecma-array-ob
|
||||
} /* ecma_op_array_is_fast_array */
|
||||
|
||||
/**
|
||||
* Allocate a new fast access mode array object with the given length
|
||||
* Allocate a new array object with the given length
|
||||
*
|
||||
* @return NULL - if the allocation of the underlying buffer failed
|
||||
* pointer to the constructed fast access mode array object otherwise
|
||||
* Note: The returned array can be normal of fast access mode
|
||||
*
|
||||
* @return pointer to the constructed array object
|
||||
*/
|
||||
ecma_object_t *
|
||||
ecma_op_new_fast_array_object (uint32_t length) /**< length of the new fast access mode array */
|
||||
ecma_op_new_array_object (uint32_t length) /**< length of the new array */
|
||||
{
|
||||
ecma_object_t *object_p = ecma_op_alloc_array_object (length);
|
||||
|
||||
const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (length);
|
||||
ecma_value_t *values_p = NULL;
|
||||
|
||||
if (length != 0)
|
||||
if (length > 0)
|
||||
{
|
||||
if (length >= ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH)
|
||||
{
|
||||
return object_p;
|
||||
}
|
||||
|
||||
values_p = (ecma_value_t *) jmem_heap_alloc_block_null_on_error (aligned_length * sizeof (ecma_value_t));
|
||||
|
||||
if (JERRY_UNLIKELY (values_p == NULL))
|
||||
{
|
||||
return NULL;
|
||||
return object_p;
|
||||
}
|
||||
}
|
||||
|
||||
ecma_object_t *object_p = ecma_op_new_array_object (length);
|
||||
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
|
||||
|
||||
ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop | ECMA_FAST_ARRAY_FLAG);
|
||||
ext_obj_p->u.array.u.hole_count += length * ECMA_FAST_ARRAY_HOLE_ONE;
|
||||
|
||||
JERRY_ASSERT (object_p->u1.property_list_cp == JMEM_CP_NULL);
|
||||
|
||||
for (uint32_t i = 0; i < aligned_length; i++)
|
||||
{
|
||||
values_p[i] = ECMA_VALUE_ARRAY_HOLE;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (object_p->u1.property_list_cp == JMEM_CP_NULL);
|
||||
ECMA_SET_POINTER (object_p->u1.property_list_cp, values_p);
|
||||
return object_p;
|
||||
} /* ecma_op_new_fast_array_object */
|
||||
} /* ecma_op_new_array_object */
|
||||
|
||||
/**
|
||||
* Allocate a new array object from the given length
|
||||
*
|
||||
* Note: The returned array can be normal of fast access mode
|
||||
*
|
||||
* @return NULL - if the given length is invalid
|
||||
* pointer to the constructed array object - otherwise
|
||||
*/
|
||||
ecma_object_t *
|
||||
ecma_op_new_array_object_from_length (ecma_length_t length) /**< length of the new array */
|
||||
{
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
if (length > UINT32_MAX)
|
||||
{
|
||||
ecma_raise_range_error (ECMA_ERR_MSG ("Invalid array length"));
|
||||
return NULL;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
return ecma_op_new_array_object ((uint32_t) length);
|
||||
} /* ecma_op_new_array_object_from_length */
|
||||
|
||||
/**
|
||||
* Allocate a new array object from the given buffer
|
||||
*
|
||||
* Note: The returned array can be normal of fast access mode
|
||||
*
|
||||
* @return ecma_value - constructed array object
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_op_new_array_object_from_buffer (const ecma_value_t *args_p, /**< array element list */
|
||||
uint32_t length) /**< number of array elements */
|
||||
{
|
||||
if (length == 0)
|
||||
{
|
||||
return ecma_make_object_value (ecma_op_new_array_object (0));
|
||||
}
|
||||
|
||||
ecma_object_t *object_p = ecma_op_alloc_array_object (length);
|
||||
const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (length);
|
||||
ecma_value_t *values_p;
|
||||
values_p = (ecma_value_t *) jmem_heap_alloc_block_null_on_error (aligned_length * sizeof (ecma_value_t));
|
||||
|
||||
if (values_p != NULL)
|
||||
{
|
||||
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
|
||||
ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop | ECMA_FAST_ARRAY_FLAG);
|
||||
JERRY_ASSERT (object_p->u1.property_list_cp == JMEM_CP_NULL);
|
||||
|
||||
for (uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
JERRY_ASSERT (!ecma_is_value_array_hole (args_p[i]));
|
||||
values_p[i] = ecma_copy_value_if_not_object (args_p[i]);
|
||||
}
|
||||
|
||||
for (uint32_t i = length; i < aligned_length; i++)
|
||||
{
|
||||
values_p[i] = ECMA_VALUE_ARRAY_HOLE;
|
||||
}
|
||||
|
||||
ECMA_SET_POINTER (object_p->u1.property_list_cp, values_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
JERRY_ASSERT (!ecma_is_value_array_hole (args_p[i]));
|
||||
|
||||
ecma_string_t *prop_name_p = ecma_new_ecma_string_from_uint32 (i);
|
||||
ecma_property_value_t *prop_value_p;
|
||||
prop_value_p = ecma_create_named_data_property (object_p,
|
||||
prop_name_p,
|
||||
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
|
||||
NULL);
|
||||
ecma_deref_ecma_string (prop_name_p);
|
||||
prop_value_p->value = ecma_copy_value_if_not_object (args_p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return ecma_make_object_value (object_p);
|
||||
} /* ecma_op_new_array_object_from_buffer */
|
||||
|
||||
/**
|
||||
* Allocate a new fast acces mode array object from the given collection
|
||||
*
|
||||
* Note: The given collection will be unavailable after and it's underlying buffer is reused
|
||||
*
|
||||
* @return ecma_value - constructed fast access mode array object
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_op_new_array_object_from_collection (ecma_collection_t *collection_p, /**< collection to create array from */
|
||||
bool unref_objects) /**< true - if the collection potentially
|
||||
containts objects
|
||||
false - otherwise */
|
||||
{
|
||||
const uint32_t item_count = collection_p->item_count;
|
||||
|
||||
if (item_count == 0)
|
||||
{
|
||||
ecma_collection_destroy (collection_p);
|
||||
return ecma_make_object_value (ecma_op_new_array_object (0));
|
||||
}
|
||||
|
||||
ecma_object_t *object_p;
|
||||
ecma_value_t *buffer_p = collection_p->buffer_p;
|
||||
const uint32_t old_size = ECMA_COLLECTION_ALLOCATED_SIZE (collection_p->capacity);
|
||||
const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (collection_p->item_count);
|
||||
|
||||
jmem_heap_free_block (collection_p, sizeof (ecma_collection_t));
|
||||
buffer_p = jmem_heap_realloc_block (buffer_p, old_size, aligned_length * sizeof (ecma_value_t));
|
||||
object_p = ecma_op_alloc_array_object (item_count);
|
||||
|
||||
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
|
||||
ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop | ECMA_FAST_ARRAY_FLAG);
|
||||
JERRY_ASSERT (object_p->u1.property_list_cp == JMEM_CP_NULL);
|
||||
JERRY_ASSERT (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE);
|
||||
ECMA_SET_POINTER (object_p->u1.property_list_cp, buffer_p);
|
||||
|
||||
if (JERRY_UNLIKELY (unref_objects))
|
||||
{
|
||||
for (uint32_t i = 0; i < item_count; i++)
|
||||
{
|
||||
/* Strong references from the collection are no longer needed
|
||||
since GC will mark these object as a fast access mode array properties */
|
||||
ecma_deref_if_object (buffer_p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = item_count; i < aligned_length; i++)
|
||||
{
|
||||
buffer_p[i] = ECMA_VALUE_ARRAY_HOLE;
|
||||
}
|
||||
|
||||
return ecma_make_object_value (object_p);
|
||||
} /* ecma_op_new_array_object_from_collection */
|
||||
|
||||
/**
|
||||
* Converts a fast access mode array back to a normal property list based array
|
||||
@@ -541,105 +682,6 @@ ecma_fast_array_object_own_property_keys (ecma_object_t *object_p) /**< fast acc
|
||||
return ret_p;
|
||||
} /* ecma_fast_array_object_own_property_keys */
|
||||
|
||||
/**
|
||||
* Array object creation operation.
|
||||
*
|
||||
* See also: ECMA-262 v5, 15.4.2.1
|
||||
* ECMA-262 v5, 15.4.2.2
|
||||
*
|
||||
* @return ecma value
|
||||
* Returned value must be freed with ecma_free_value
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of arguments that
|
||||
* are passed to Array constructor */
|
||||
uint32_t arguments_list_len, /**< length of the arguments' list */
|
||||
bool is_treat_single_arg_as_length) /**< if the value is true,
|
||||
* arguments_list_len is 1
|
||||
* and single argument is Number,
|
||||
* then treat the single argument
|
||||
* as new Array's length rather
|
||||
* than as single item of the Array */
|
||||
{
|
||||
JERRY_ASSERT (arguments_list_len == 0
|
||||
|| arguments_list_p != NULL);
|
||||
|
||||
uint32_t length;
|
||||
const ecma_value_t *array_items_p;
|
||||
uint32_t array_items_count;
|
||||
|
||||
if (is_treat_single_arg_as_length
|
||||
&& arguments_list_len == 1
|
||||
&& ecma_is_value_number (arguments_list_p[0]))
|
||||
{
|
||||
ecma_number_t num = ecma_get_number_from_value (arguments_list_p[0]);
|
||||
uint32_t num_uint32 = ecma_number_to_uint32 (num);
|
||||
|
||||
if (num != ((ecma_number_t) num_uint32))
|
||||
{
|
||||
return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid array length."));
|
||||
}
|
||||
else
|
||||
{
|
||||
length = num_uint32;
|
||||
array_items_p = NULL;
|
||||
array_items_count = 0;
|
||||
}
|
||||
|
||||
if (length > ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH)
|
||||
{
|
||||
return ecma_make_object_value (ecma_op_new_array_object (length));
|
||||
}
|
||||
|
||||
ecma_object_t *object_p = ecma_op_new_fast_array_object (length);
|
||||
|
||||
if (object_p == NULL)
|
||||
{
|
||||
return ecma_make_object_value (ecma_op_new_array_object (length));
|
||||
}
|
||||
|
||||
JERRY_ASSERT (ecma_op_object_is_fast_array (object_p));
|
||||
|
||||
return ecma_make_object_value (object_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
length = arguments_list_len;
|
||||
array_items_p = arguments_list_p;
|
||||
array_items_count = arguments_list_len;
|
||||
}
|
||||
|
||||
ecma_object_t *object_p = ecma_op_new_fast_array_object (length);
|
||||
|
||||
/* At this point we were not able to allocate a length * sizeof (ecma_value_t) amount of memory,
|
||||
so we can terminate the engine since converting it into normal property list based array
|
||||
would consume more memory. */
|
||||
if (object_p == NULL)
|
||||
{
|
||||
jerry_fatal (ERR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return ecma_make_object_value (object_p);
|
||||
}
|
||||
|
||||
ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
|
||||
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
|
||||
|
||||
for (uint32_t index = 0;
|
||||
index < array_items_count;
|
||||
index++)
|
||||
{
|
||||
JERRY_ASSERT (!ecma_is_value_array_hole (array_items_p[index]));
|
||||
values_p[index] = ecma_copy_value_if_not_object (array_items_p[index]);
|
||||
}
|
||||
|
||||
ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE * array_items_count;
|
||||
|
||||
return ecma_make_object_value (object_p);
|
||||
} /* ecma_op_create_array_object */
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
/**
|
||||
* Array object creation with custom prototype.
|
||||
@@ -649,7 +691,7 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of
|
||||
* @return ecma value
|
||||
* Returned value must be freed with ecma_free_value
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_object_t *
|
||||
ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object from whom the new array object
|
||||
* is being created */
|
||||
ecma_length_t length) /**< length of the array */
|
||||
@@ -661,7 +703,7 @@ ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object f
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (is_array))
|
||||
{
|
||||
return is_array;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ecma_is_value_true (is_array))
|
||||
@@ -669,7 +711,7 @@ ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object f
|
||||
constructor = ecma_op_object_get_by_magic_id (original_array_p, LIT_MAGIC_STRING_CONSTRUCTOR);
|
||||
if (ECMA_IS_VALUE_ERROR (constructor))
|
||||
{
|
||||
return constructor;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ecma_is_constructor (constructor)
|
||||
@@ -686,7 +728,7 @@ ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object f
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (constructor))
|
||||
{
|
||||
return constructor;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ecma_is_value_null (constructor))
|
||||
@@ -698,17 +740,14 @@ ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object f
|
||||
|
||||
if (ecma_is_value_undefined (constructor))
|
||||
{
|
||||
ecma_value_t length_val = ecma_make_length_value (length);
|
||||
ecma_value_t new_array = ecma_op_create_array_object (&length_val, 1, true);
|
||||
ecma_free_value (length_val);
|
||||
|
||||
return new_array;
|
||||
return ecma_op_new_array_object_from_length (length);
|
||||
}
|
||||
|
||||
if (!ecma_is_constructor (constructor))
|
||||
{
|
||||
ecma_free_value (constructor);
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid species constructor"));
|
||||
ecma_raise_type_error (ECMA_ERR_MSG ("Invalid species constructor"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ecma_value_t len_val = ecma_make_length_value (length);
|
||||
@@ -720,7 +759,13 @@ ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object f
|
||||
|
||||
ecma_deref_object (ctor_object_p);
|
||||
ecma_free_value (len_val);
|
||||
return ret_val;
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (ret_val))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ecma_get_object_from_value (ret_val);
|
||||
} /* ecma_op_array_species_create */
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user