Skip to content

Implement built-in flag support for arguments #4774

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 1 commit into from
Sep 22, 2021
Merged
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
7 changes: 3 additions & 4 deletions jerry-core/ecma/base/ecma-globals.h
Original file line number Diff line number Diff line change
@@ -223,7 +223,7 @@ enum
ECMA_VALUE_SPREAD_ELEMENT = ECMA_MAKE_VALUE (11), /**< a special value for spread elements in array initialization
* or function call argument list */
/* Other values */
ECMA_VALUE_INITIALIZED = ECMA_MAKE_VALUE (12), /**< represents initialized mapped arguments formal parameter */
ECMA_VALUE_ARGUMENT_NO_TRACK = ECMA_MAKE_VALUE (12), /**< represents not-tracked arguments formal parameter */
#if JERRY_ESNEXT
ECMA_VALUE_SYNC_ITERATOR = ECMA_MAKE_VALUE (13), /**< option for ecma_op_get_iterator: sync iterator is requested */
ECMA_VALUE_ASYNC_ITERATOR = ECMA_MAKE_VALUE (14), /**< option for ecma_op_get_iterator: async iterator is requested */
@@ -2452,9 +2452,8 @@ typedef enum
ECMA_ARGUMENTS_OBJECT_MAPPED = (1 << 0), /* mapped arguments object */
ECMA_ARGUMENTS_OBJECT_STATIC_BYTECODE = (1 << 1), /* static mapped arguments object */
ECMA_ARGUMENTS_OBJECT_CALLEE_INITIALIZED = (1 << 2), /* 'callee' property has been lazy initialized */
ECMA_ARGUMENTS_OBJECT_CALLER_INITIALIZED = (1 << 3), /* 'caller' property has been lazy initialized */
ECMA_ARGUMENTS_OBJECT_LENGTH_INITIALIZED = (1 << 4), /* 'length' property has been lazy initialized */
ECMA_ARGUMENTS_OBJECT_ITERATOR_INITIALIZED = (1 << 5), /* 'Symbol.iterator' property has been lazy initialized */
ECMA_ARGUMENTS_OBJECT_LENGTH_INITIALIZED = (1 << 3), /* 'length' property has been lazy initialized */
ECMA_ARGUMENTS_OBJECT_ITERATOR_INITIALIZED = (1 << 4), /* 'Symbol.iterator' property has been lazy initialized */
} ecma_arguments_object_flags_t;

/**
205 changes: 102 additions & 103 deletions jerry-core/ecma/operations/ecma-arguments-object.c
Original file line number Diff line number Diff line change
@@ -88,7 +88,7 @@ ecma_op_create_arguments_object (vm_frame_ctx_shared_args_t *shared_p, /**< shar

for (uint32_t i = shared_p->arg_list_len; i < saved_arg_count; i++)
{
argv_p[i] = ECMA_VALUE_INITIALIZED;
argv_p[i] = ECMA_VALUE_UNDEFINED;
}

arguments_p->header.u.cls.u3.arguments_number = shared_p->arg_list_len;
@@ -137,7 +137,7 @@ ecma_op_create_arguments_object (vm_frame_ctx_shared_args_t *shared_p, /**< shar

ecma_deref_ecma_string (prop_name_p);

prop_value_p->value = argv_p[i] == ECMA_VALUE_INITIALIZED ? ECMA_VALUE_UNDEFINED : argv_p[i];
prop_value_p->value = argv_p[i];
argv_p[i] = ECMA_VALUE_EMPTY;
}
}
@@ -183,76 +183,40 @@ ecma_op_arguments_object_define_own_property (ecma_object_t *object_p, /**< the

ecma_value_t *argv_p = (ecma_value_t *) (mapped_arguments_p + 1);

if (!ecma_is_value_empty (argv_p[index]))
if (ecma_is_value_empty (argv_p[index]) || argv_p[index] == ECMA_VALUE_ARGUMENT_NO_TRACK)
{
if (property_desc_p->flags & (JERRY_PROP_IS_GET_DEFINED | JERRY_PROP_IS_SET_DEFINED))
{
ecma_free_value_if_not_object (argv_p[index]);
argv_p[index] = ECMA_VALUE_EMPTY;
}
else
{
if (property_desc_p->flags & JERRY_PROP_IS_VALUE_DEFINED)
{
ecma_string_t *name_p = ecma_op_arguments_object_get_formal_parameter (mapped_arguments_p, index);
ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, mapped_arguments_p->lex_env);

ecma_value_t completion = ecma_op_set_mutable_binding (lex_env_p,
name_p,
property_desc_p->value,
true);

JERRY_ASSERT (ecma_is_value_empty (completion));
}

if ((property_desc_p->flags & JERRY_PROP_IS_WRITABLE_DEFINED)
&& !(property_desc_p->flags & JERRY_PROP_IS_WRITABLE))
{
ecma_free_value_if_not_object (argv_p[index]);
argv_p[index] = ECMA_VALUE_EMPTY;
}
}
return ret_value;
}

return ret_value;
} /* ecma_op_arguments_object_define_own_property */

/**
* [[Delete]] ecma Arguments object's operation
*
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
* ECMA-262 v5, 10.6
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_arguments_object_delete (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p, /**< property name */
bool is_throw) /**< flag that controls failure handling */
{
/* 3. */
ecma_value_t ret_value = ecma_op_general_object_delete (object_p, property_name_p, is_throw);

if (!ecma_is_value_true (ret_value)
|| !(((ecma_extended_object_t *) object_p)->u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_MAPPED))
if (property_desc_p->flags & (JERRY_PROP_IS_GET_DEFINED | JERRY_PROP_IS_SET_DEFINED))
{
ecma_free_value_if_not_object (argv_p[index]);
argv_p[index] = ECMA_VALUE_ARGUMENT_NO_TRACK;
return ret_value;
}

ecma_mapped_arguments_t *mapped_arguments_p = (ecma_mapped_arguments_t *) object_p;
ecma_value_t *argv_p = (ecma_value_t *) (mapped_arguments_p + 1);
uint32_t index = ecma_string_get_array_index (property_name_p);
if (property_desc_p->flags & JERRY_PROP_IS_VALUE_DEFINED)
{
ecma_string_t *name_p = ecma_op_arguments_object_get_formal_parameter (mapped_arguments_p, index);
ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, mapped_arguments_p->lex_env);

ecma_value_t completion = ecma_op_set_mutable_binding (lex_env_p,
name_p,
property_desc_p->value,
true);

if (index < mapped_arguments_p->unmapped.header.u.cls.u2.formal_params_number)
JERRY_ASSERT (ecma_is_value_empty (completion));
}

if ((property_desc_p->flags & JERRY_PROP_IS_WRITABLE_DEFINED)
&& !(property_desc_p->flags & JERRY_PROP_IS_WRITABLE))
{
ecma_free_value_if_not_object (argv_p[index]);
argv_p[index] = ECMA_VALUE_EMPTY;
argv_p[index] = ECMA_VALUE_ARGUMENT_NO_TRACK;
}

return ret_value;
} /* ecma_op_arguments_object_delete */
} /* ecma_op_arguments_object_define_own_property */

/**
* Try to lazy instantiate the given property of a mapped/unmapped arguments object
@@ -269,7 +233,7 @@ ecma_op_arguments_object_try_to_lazy_instantiate_property (ecma_object_t *object
ecma_unmapped_arguments_t *arguments_p = (ecma_unmapped_arguments_t *) object_p;
ecma_value_t *argv_p = (ecma_value_t *) (arguments_p + 1);
ecma_property_value_t *prop_value_p;
ecma_property_t *prop_p = NULL;
ecma_property_t *prop_p;
uint32_t arguments_number = arguments_p->header.u.cls.u3.arguments_number;
uint8_t flags = arguments_p->header.u.cls.u1.arguments_flags;

@@ -283,57 +247,45 @@ ecma_op_arguments_object_try_to_lazy_instantiate_property (ecma_object_t *object
if (index != ECMA_STRING_NOT_ARRAY_INDEX)
{
if (index >= arguments_number
|| ecma_is_value_empty (argv_p[index])
|| argv_p[index] == ECMA_VALUE_INITIALIZED)
|| ecma_is_value_empty (argv_p[index]))
{
return NULL;
}

JERRY_ASSERT (argv_p[index] != ECMA_VALUE_ARGUMENT_NO_TRACK);

prop_value_p = ecma_create_named_data_property (object_p,
property_name_p,
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
ECMA_PROPERTY_BUILT_IN_CONFIGURABLE_ENUMERABLE_WRITABLE,
&prop_p);

/* Passing the reference */
prop_value_p->value = argv_p[index];

/* Pevent reinitialization */
if ((flags & ECMA_ARGUMENTS_OBJECT_MAPPED)
&& index < arguments_p->header.u.cls.u2.formal_params_number)
{
argv_p[index] = ECMA_VALUE_INITIALIZED;
}
else
{
argv_p[index] = ECMA_VALUE_EMPTY;
}

argv_p[index] = ECMA_VALUE_UNDEFINED;
return prop_p;
}

if (property_name_p == ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH)
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_LENGTH)
&& !(flags & ECMA_ARGUMENTS_OBJECT_LENGTH_INITIALIZED))
{
arguments_p->header.u.cls.u1.arguments_flags |= ECMA_ARGUMENTS_OBJECT_LENGTH_INITIALIZED;

prop_value_p = ecma_create_named_data_property (object_p,
ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH),
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
ECMA_PROPERTY_BUILT_IN_CONFIGURABLE_WRITABLE,
&prop_p);

prop_value_p->value = ecma_make_uint32_value (arguments_number);
return prop_p;
}

if (property_name_p == ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE)
if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_CALLEE)
&& !(flags & ECMA_ARGUMENTS_OBJECT_CALLEE_INITIALIZED))
{
arguments_p->header.u.cls.u1.arguments_flags |= ECMA_ARGUMENTS_OBJECT_CALLEE_INITIALIZED;

if (flags & ECMA_ARGUMENTS_OBJECT_MAPPED)
{
prop_value_p = ecma_create_named_data_property (object_p,
property_name_p,
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
ECMA_PROPERTY_BUILT_IN_CONFIGURABLE_WRITABLE,
&prop_p);

prop_value_p->value = arguments_p->callee;
@@ -346,75 +298,120 @@ ecma_op_arguments_object_try_to_lazy_instantiate_property (ecma_object_t *object
ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE),
thrower_p,
thrower_p,
ECMA_PROPERTY_FIXED,
ECMA_PROPERTY_BUILT_IN_FIXED,
&prop_p);
}
return prop_p;
}

#if !JERRY_ESNEXT
if (property_name_p == ecma_get_magic_string (LIT_MAGIC_STRING_CALLER)
&& !(arguments_p->header.u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_CALLER_INITIALIZED))
if (property_name_p == ecma_get_magic_string (LIT_MAGIC_STRING_CALLER))
{
if (arguments_p->header.u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_MAPPED)
{
return NULL;
}

arguments_p->header.u.cls.u1.arguments_flags |= ECMA_ARGUMENTS_OBJECT_CALLER_INITIALIZED;

ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);

ecma_create_named_accessor_property (object_p,
ecma_get_magic_string (LIT_MAGIC_STRING_CALLER),
thrower_p,
thrower_p,
ECMA_PROPERTY_FIXED,
ECMA_PROPERTY_BUILT_IN_FIXED,
&prop_p);
return prop_p;
}
#else /* JERRY_ESNEXT */
ecma_string_t *symbol_p = ecma_op_get_global_symbol (LIT_GLOBAL_SYMBOL_ITERATOR);

if (property_name_p == symbol_p
if (ecma_op_compare_string_to_global_symbol (property_name_p, LIT_GLOBAL_SYMBOL_ITERATOR)
&& !(flags & ECMA_ARGUMENTS_OBJECT_ITERATOR_INITIALIZED))
{
arguments_p->header.u.cls.u1.arguments_flags |= ECMA_ARGUMENTS_OBJECT_ITERATOR_INITIALIZED;

prop_value_p = ecma_create_named_data_property (object_p,
symbol_p,
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
property_name_p,
ECMA_PROPERTY_BUILT_IN_CONFIGURABLE_WRITABLE,
&prop_p);

prop_value_p->value = ecma_op_object_get_by_magic_id (ecma_builtin_get (ECMA_BUILTIN_ID_INTRINSIC_OBJECT),
LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES);

JERRY_ASSERT (ecma_is_value_object (prop_value_p->value));
ecma_deref_object (ecma_get_object_from_value (prop_value_p->value));
return prop_p;
}

ecma_deref_ecma_string (symbol_p);
#endif /* !JERRY_ESNEXT */

return prop_p;
return NULL;
} /* ecma_op_arguments_object_try_to_lazy_instantiate_property */

/**
* Delete configurable properties of arguments object
*/
void
ecma_op_arguments_delete_built_in_property (ecma_object_t *object_p, /**< the object */
ecma_string_t *property_name_p) /**< property name */
{
ecma_unmapped_arguments_t *arguments_p = (ecma_unmapped_arguments_t *) object_p;

if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_LENGTH))
{
JERRY_ASSERT (!(arguments_p->header.u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_LENGTH_INITIALIZED));

arguments_p->header.u.cls.u1.arguments_flags |= ECMA_ARGUMENTS_OBJECT_LENGTH_INITIALIZED;
return;
}

if (ecma_compare_ecma_string_to_magic_id (property_name_p, LIT_MAGIC_STRING_CALLEE))
{
JERRY_ASSERT (!(arguments_p->header.u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_CALLEE_INITIALIZED));
JERRY_ASSERT (arguments_p->header.u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_MAPPED);

arguments_p->header.u.cls.u1.arguments_flags |= ECMA_ARGUMENTS_OBJECT_CALLEE_INITIALIZED;
return;
}

#if JERRY_ESNEXT
if (ecma_prop_name_is_symbol (property_name_p))
{
JERRY_ASSERT (!(arguments_p->header.u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_ITERATOR_INITIALIZED));
JERRY_ASSERT (ecma_op_compare_string_to_global_symbol (property_name_p, LIT_GLOBAL_SYMBOL_ITERATOR));

arguments_p->header.u.cls.u1.arguments_flags |= ECMA_ARGUMENTS_OBJECT_ITERATOR_INITIALIZED;
return;
}
#endif /* JERRY_ESNEXT */

uint32_t index = ecma_string_get_array_index (property_name_p);

ecma_value_t *argv_p = (ecma_value_t *) (arguments_p + 1);

if (arguments_p->header.u.cls.u1.arguments_flags & ECMA_ARGUMENTS_OBJECT_MAPPED)
{
argv_p = (ecma_value_t *) (((ecma_mapped_arguments_t *) object_p) + 1);
}

JERRY_ASSERT (argv_p[index] == ECMA_VALUE_UNDEFINED
|| argv_p[index] == ECMA_VALUE_ARGUMENT_NO_TRACK);

argv_p[index] = ECMA_VALUE_EMPTY;
} /* ecma_op_arguments_delete_built_in_property */

/**
* List names of an arguments object's lazy instantiated properties
*/
void
ecma_op_arguments_object_list_lazy_property_names (ecma_object_t *obj_p, /**< arguments object */
ecma_collection_t *prop_names_p, /**< prop name collection */
ecma_property_counter_t *prop_counter_p) /**< prop counter */
ecma_property_counter_t *prop_counter_p) /**< property counters */
{
JERRY_ASSERT (ecma_object_class_is (obj_p, ECMA_OBJECT_CLASS_ARGUMENTS));

ecma_unmapped_arguments_t *arguments_p = (ecma_unmapped_arguments_t *) obj_p;

ecma_value_t *argv_p = (ecma_value_t *) (arguments_p + 1);
uint32_t arguments_number = arguments_p->header.u.cls.u3.arguments_number;
uint8_t flags = arguments_p->header.u.cls.u1.arguments_flags;

ecma_value_t *argv_p = (ecma_value_t *) (arguments_p + 1);

if (flags & ECMA_ARGUMENTS_OBJECT_MAPPED)
{
argv_p = (ecma_value_t *) (((ecma_mapped_arguments_t *) obj_p) + 1);
@@ -443,19 +440,21 @@ ecma_op_arguments_object_list_lazy_property_names (ecma_object_t *obj_p, /**< ar
}

#if !JERRY_ESNEXT
if (!(flags & (ECMA_ARGUMENTS_OBJECT_CALLER_INITIALIZED | ECMA_ARGUMENTS_OBJECT_MAPPED)))
if (!(flags & ECMA_ARGUMENTS_OBJECT_MAPPED))
{
ecma_collection_push_back (prop_names_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_CALLER));
prop_counter_p->string_named_props++;
}
#else /* JERRY_ESNEXT */
#endif /* !JERRY_ESNEXT */

#if JERRY_ESNEXT
if (!(flags & ECMA_ARGUMENTS_OBJECT_ITERATOR_INITIALIZED))
{
ecma_string_t *symbol_p = ecma_op_get_global_symbol (LIT_GLOBAL_SYMBOL_ITERATOR);
ecma_collection_push_back (prop_names_p, ecma_make_symbol_value (symbol_p));
prop_counter_p->symbol_named_props++;
}
#endif /* !JERRY_ESNEXT */
#endif /* JERRY_ESNEXT */
} /* ecma_op_arguments_object_list_lazy_property_names */

/**
8 changes: 4 additions & 4 deletions jerry-core/ecma/operations/ecma-arguments-object.h
Original file line number Diff line number Diff line change
@@ -23,8 +23,6 @@
ecma_value_t
ecma_op_create_arguments_object (vm_frame_ctx_shared_args_t *shared_p, ecma_object_t *lex_env_p);

ecma_value_t
ecma_op_arguments_object_delete (ecma_object_t *object_p, ecma_string_t *property_name_p, bool is_throw);
ecma_value_t
ecma_op_arguments_object_define_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p,
const ecma_property_descriptor_t *property_desc_p);
@@ -34,8 +32,10 @@ ecma_op_arguments_object_try_to_lazy_instantiate_property (ecma_object_t *object
ecma_string_t *property_name_p);

void
ecma_op_arguments_object_list_lazy_property_names (ecma_object_t *obj_p,
ecma_collection_t *prop_names_p,
ecma_op_arguments_delete_built_in_property (ecma_object_t *object_p, ecma_string_t *property_name_p);

void
ecma_op_arguments_object_list_lazy_property_names (ecma_object_t *obj_p, ecma_collection_t *prop_names_p,
ecma_property_counter_t *prop_counter_p);

ecma_string_t *
Loading