Skip to content

Commit

Permalink
Disguise accessor properties as data properties
Browse files Browse the repository at this point in the history
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg [email protected]
  • Loading branch information
zherczeg committed Dec 29, 2020
1 parent c9b1655 commit 4598550
Show file tree
Hide file tree
Showing 10 changed files with 453 additions and 18 deletions.
24 changes: 17 additions & 7 deletions jerry-core/api/jerry.c
Original file line number Diff line number Diff line change
Expand Up @@ -3065,6 +3065,7 @@ jerry_init_property_descriptor_fields (jerry_property_descriptor_t *prop_desc_p)
prop_desc_p->is_enumerable = false;
prop_desc_p->is_configurable_defined = false;
prop_desc_p->is_configurable = false;
prop_desc_p->is_data_accessor = false;
prop_desc_p->is_get_defined = false;
prop_desc_p->getter = ECMA_VALUE_UNDEFINED;
prop_desc_p->is_set_defined = false;
Expand All @@ -3084,31 +3085,33 @@ jerry_property_descriptor_from_ecma (const ecma_property_descriptor_t *prop_desc
jerry_property_descriptor_t prop_desc;
jerry_init_property_descriptor_fields (&prop_desc);

if (prop_desc_p->flags & (ECMA_PROP_IS_ENUMERABLE_DEFINED))
if (prop_desc_p->flags & ECMA_PROP_IS_ENUMERABLE_DEFINED)
{
prop_desc.is_enumerable_defined = true;
prop_desc.is_enumerable = prop_desc_p->flags & (ECMA_PROP_IS_ENUMERABLE);
prop_desc.is_enumerable = (prop_desc_p->flags & ECMA_PROP_IS_ENUMERABLE) != 0;
}

if (prop_desc_p->flags & (ECMA_PROP_IS_CONFIGURABLE_DEFINED))
if (prop_desc_p->flags & ECMA_PROP_IS_CONFIGURABLE_DEFINED)
{
prop_desc.is_configurable_defined = true;
prop_desc.is_configurable = prop_desc_p->flags & (ECMA_PROP_IS_CONFIGURABLE);
prop_desc.is_configurable = (prop_desc_p->flags & ECMA_PROP_IS_CONFIGURABLE) != 0;
}

prop_desc.is_value_defined = prop_desc_p->flags & (ECMA_PROP_IS_VALUE_DEFINED);
prop_desc.is_value_defined = (prop_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED) != 0;

if (prop_desc.is_value_defined)
{
prop_desc.value = prop_desc_p->value;
}

if (prop_desc_p->flags & (ECMA_PROP_IS_WRITABLE_DEFINED))
if (prop_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
{
prop_desc.is_writable_defined = true;
prop_desc.is_writable = prop_desc_p->flags & (ECMA_PROP_IS_WRITABLE);
prop_desc.is_writable = (prop_desc_p->flags & ECMA_PROP_IS_WRITABLE) != 0;
}

prop_desc.is_data_accessor = (prop_desc_p->flags & ECMA_PROP_IS_DATA_ACCESSOR) != 0;

if (prop_desc_p->flags & (ECMA_PROP_IS_GET_DEFINED))
{
ecma_value_t getter = ecma_make_object_value (prop_desc_p->get_p);
Expand Down Expand Up @@ -3176,6 +3179,11 @@ jerry_property_descriptor_to_ecma (const jerry_property_descriptor_t *prop_desc_
: ECMA_PROP_NO_OPTS));
}

if (prop_desc_p->is_data_accessor)
{
flags |= ECMA_PROP_IS_DATA_ACCESSOR;
}

/* Copy accessor property info. */
if (prop_desc_p->is_get_defined)
{
Expand Down Expand Up @@ -3311,6 +3319,8 @@ jerry_get_own_property_descriptor (const jerry_value_t obj_val, /**< object val
prop_desc_p->is_writable_defined = (prop_desc.flags & ECMA_PROP_IS_WRITABLE_DEFINED) != 0;
prop_desc_p->is_writable = prop_desc_p->is_writable_defined ? (prop_desc.flags & ECMA_PROP_IS_WRITABLE) != 0 : false;

prop_desc_p->is_data_accessor = (prop_desc.flags & ECMA_PROP_IS_DATA_ACCESSOR) != 0;

prop_desc_p->is_value_defined = (prop_desc.flags & ECMA_PROP_IS_VALUE_DEFINED) != 0;
prop_desc_p->is_get_defined = (prop_desc.flags & ECMA_PROP_IS_GET_DEFINED) != 0;
prop_desc_p->is_set_defined = (prop_desc.flags & ECMA_PROP_IS_SET_DEFINED) != 0;
Expand Down
3 changes: 2 additions & 1 deletion jerry-core/ecma/base/ecma-globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ typedef enum
ECMA_PROPERTY_FLAG_CONFIGURABLE = 1u << 2, /**< property is configurable */
ECMA_PROPERTY_FLAG_ENUMERABLE = 1u << 3, /**< property is enumerable */
ECMA_PROPERTY_FLAG_WRITABLE = 1u << 4, /**< property is writable */
ECMA_PROPERTY_FLAG_DATA_ACCESSOR = 1u << 4, /**< property is data accessor */
ECMA_PROPERTY_FLAG_DATA = 1u << 5, /**< property contains data */
} ecma_property_flags_t;

Expand Down Expand Up @@ -1155,6 +1156,7 @@ typedef enum
ECMA_PROP_IS_CONFIGURABLE_DEFINED = (1 << 7), /** Is [[Configurable]] defined? */
ECMA_PROP_IS_ENUMERABLE_DEFINED = (1 << 8), /** Is [[Enumerable]] defined? */
ECMA_PROP_IS_WRITABLE_DEFINED = (1 << 9), /** Is [[Writable]] defined? */
ECMA_PROP_IS_DATA_ACCESSOR = (1 << 10), /** Is data accessor */
} ecma_property_descriptor_status_flags_t;

/**
Expand All @@ -1169,7 +1171,6 @@ typedef enum
*/
typedef struct
{

/** any combination of ecma_property_descriptor_status_flags_t bits */
uint16_t flags;

Expand Down
2 changes: 1 addition & 1 deletion jerry-core/ecma/base/ecma-helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ ecma_create_named_accessor_property (ecma_object_t *object_p, /**< object */
JERRY_ASSERT (ecma_is_lexical_environment (object_p)
|| !ecma_op_object_is_fast_array (object_p));
JERRY_ASSERT (ecma_find_named_property (object_p, name_p) == NULL);
JERRY_ASSERT ((prop_attributes & ~ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE) == 0);
JERRY_ASSERT ((prop_attributes & ~(ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE | ECMA_PROPERTY_FLAG_DATA_ACCESSOR)) == 0);

uint8_t type_and_flags = prop_attributes;

Expand Down
25 changes: 25 additions & 0 deletions jerry-core/ecma/builtin-objects/ecma-builtin-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,17 @@ ecma_builtin_object_object_get_own_property_descriptor (ecma_object_t *obj_p, /*

if (ecma_is_value_true (status))
{
if (JERRY_UNLIKELY (prop_desc.flags & ECMA_PROP_IS_DATA_ACCESSOR))
{
status = ecma_op_to_data_property (obj_p, &prop_desc);

if (ECMA_IS_VALUE_ERROR (status))
{
ecma_free_property_descriptor (&prop_desc);
return status;
}
}

/* 4. */
ecma_object_t *desc_obj_p = ecma_op_from_property_descriptor (&prop_desc);

Expand Down Expand Up @@ -786,6 +797,20 @@ ecma_builtin_object_object_get_own_property_descriptors (ecma_object_t *obj_p) /

if (ecma_is_value_true (status))
{
if (JERRY_UNLIKELY (prop_desc.flags & ECMA_PROP_IS_DATA_ACCESSOR))
{
status = ecma_op_to_data_property (obj_p, &prop_desc);

if (ECMA_IS_VALUE_ERROR (status))
{
ecma_free_property_descriptor (&prop_desc);
ecma_deref_object (descriptors_p);
ecma_collection_free (prop_names_p);

return status;
}
}

/* 4.b */
ecma_object_t *desc_obj_p = ecma_op_from_property_descriptor (&prop_desc);
/* 4.c */
Expand Down
44 changes: 44 additions & 0 deletions jerry-core/ecma/operations/ecma-conversion.c
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,50 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */
return ret_value;
} /* ecma_op_to_property_descriptor */

/**
* Convert accessor to data property.
*
* @return ECMA_VALUE_EMPTY - if the opertation is successful
* error - otherwise
*/
ecma_value_t
ecma_op_to_data_property (ecma_object_t *object_p, /**< base object */
ecma_property_descriptor_t *prop_desc_p) /**< [in/out] property descriptor */
{
JERRY_ASSERT (prop_desc_p->flags & ECMA_PROP_IS_DATA_ACCESSOR);

ecma_value_t result = ECMA_VALUE_UNDEFINED;
uint16_t flags = prop_desc_p->flags;

if ((flags & ECMA_PROP_IS_GET_DEFINED) && prop_desc_p->get_p != NULL)
{
result = ecma_op_function_call (prop_desc_p->get_p, ecma_make_object_value (object_p), NULL, 0);

if (ECMA_IS_VALUE_ERROR (result))
{
return result;
}

ecma_deref_object (prop_desc_p->get_p);
prop_desc_p->get_p = NULL;
}

if ((flags & ECMA_PROP_IS_SET_DEFINED) && prop_desc_p->set_p != NULL)
{
ecma_deref_object (prop_desc_p->set_p);
prop_desc_p->set_p = NULL;

flags |= ECMA_PROP_IS_WRITABLE;
}

flags |= ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_VALUE_DEFINED;
flags &= (uint16_t) ~(ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED | ECMA_PROP_IS_DATA_ACCESSOR);

prop_desc_p->value = result;
prop_desc_p->flags = flags;
return ECMA_VALUE_EMPTY;
} /* ecma_op_to_data_property */

/**
* IsInteger operation.
*
Expand Down
1 change: 1 addition & 0 deletions jerry-core/ecma/operations/ecma-conversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ ecma_collection_t *ecma_op_create_list_from_array_like (ecma_value_t arr, bool p

ecma_object_t *ecma_op_from_property_descriptor (const ecma_property_descriptor_t *src_prop_desc_p);
ecma_value_t ecma_op_to_property_descriptor (ecma_value_t obj_value, ecma_property_descriptor_t *out_prop_desc_p);
ecma_value_t ecma_op_to_data_property (ecma_object_t *object_p, ecma_property_descriptor_t *prop_desc_p);

/**
* @}
Expand Down
97 changes: 90 additions & 7 deletions jerry-core/ecma/operations/ecma-objects-general.c
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,11 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob
else
{
/* b. */
if (property_desc_p->flags & ECMA_PROP_IS_DATA_ACCESSOR)
{
prop_attributes |= ECMA_PROPERTY_FLAG_DATA_ACCESSOR;
}

ecma_create_named_accessor_property (object_p,
property_name_p,
property_desc_p->get_p,
Expand Down Expand Up @@ -503,15 +508,9 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob
}
}
}
else
else if (is_current_configurable)
{
/* 9. */
if (!is_current_configurable)
{
/* a. */
return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW);
}

ecma_property_value_t *value_p = ext_property_ref.property_ref.value_p;

if (property_desc_type == ECMA_OP_OBJECT_DEFINE_ACCESSOR)
Expand Down Expand Up @@ -548,6 +547,81 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob
prop_flags ^= ECMA_PROPERTY_FLAG_DATA;
*(ext_property_ref.property_p) = prop_flags;
}
else
{
/* Property is non-configurable. */
if ((current_prop & ECMA_PROPERTY_FLAG_DATA)
|| !(current_prop & ECMA_PROPERTY_FLAG_DATA_ACCESSOR))
{
/* a. */
return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW);
}

/* Non-standard extension. */
ecma_getter_setter_pointers_t *getter_setter_pair_p;
getter_setter_pair_p = ecma_get_named_accessor_property (ext_property_ref.property_ref.value_p);

if (getter_setter_pair_p->setter_cp == JMEM_CP_NULL)
{
const uint16_t mask = ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_WRITABLE;

if ((property_desc_p->flags & mask) == mask)
{
return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW);
}

if (!(property_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED))
{
return ECMA_VALUE_TRUE;
}

ecma_value_t result = ECMA_VALUE_UNDEFINED;

if (getter_setter_pair_p->getter_cp != JMEM_CP_NULL)
{
ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, getter_setter_pair_p->getter_cp);
result = ecma_op_function_call (getter_p, ecma_make_object_value (object_p), NULL, 0);

if (ECMA_IS_VALUE_ERROR (result))
{
return result;
}
}

bool same_value = ecma_op_same_value (property_desc_p->value, result);
ecma_free_value (result);

if (!same_value)
{
return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW);
}
return ECMA_VALUE_TRUE;
}

if (property_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED)
{
ecma_object_t *setter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, getter_setter_pair_p->setter_cp);

ecma_value_t result;
result = ecma_op_function_call (setter_p, ecma_make_object_value (object_p), &property_desc_p->value, 1);

if (ECMA_IS_VALUE_ERROR (result))
{
return result;
}

ecma_free_value (result);
}

/* Because the property is non-configurable, it cannot be modified. */
if ((property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
&& !(property_desc_p->flags & ECMA_PROP_IS_WRITABLE))
{
getter_setter_pair_p->setter_cp = JMEM_CP_NULL;
}

return ECMA_VALUE_TRUE;
}

/* 12. */
if (property_desc_type == ECMA_OP_OBJECT_DEFINE_DATA)
Expand Down Expand Up @@ -583,6 +657,15 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob
ext_property_ref.property_ref.value_p,
property_desc_p->set_p);
}

if (property_desc_p->flags & ECMA_PROP_IS_DATA_ACCESSOR)
{
*ext_property_ref.property_p |= ECMA_PROPERTY_FLAG_DATA_ACCESSOR;
}
else
{
*ext_property_ref.property_p &= (uint8_t) ~ECMA_PROPERTY_FLAG_DATA_ACCESSOR;
}
}

if (property_desc_p->flags & ECMA_PROP_IS_ENUMERABLE_DEFINED)
Expand Down
9 changes: 7 additions & 2 deletions jerry-core/ecma/operations/ecma-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@
* See also:
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
*
* @return pointer to a property - if it exists,
* NULL (i.e. ecma-undefined) - otherwise.
* @return property descriptor - if it exists,
* ECMA_PROPERTY_TYPE_NOT_FOUND / ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP - otherwise.
*/
ecma_property_t
ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */
Expand Down Expand Up @@ -1913,6 +1913,11 @@ ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the ob
prop_desc_p->set_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->setter_cp);
ecma_ref_object (prop_desc_p->set_p);
}

if (property & ECMA_PROPERTY_FLAG_DATA_ACCESSOR)
{
prop_desc_p->flags |= ECMA_PROP_IS_DATA_ACCESSOR;
}
}

return ECMA_VALUE_TRUE;
Expand Down
3 changes: 3 additions & 0 deletions jerry-core/include/jerryscript-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ typedef struct
/** [[Configurable]] */
bool is_configurable;

/** Is data accessor property */
bool is_data_accessor;

/** [[Value]] */
jerry_value_t value;

Expand Down
Loading

0 comments on commit 4598550

Please sign in to comment.