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 23, 2020
1 parent 33c0413 commit 8e29bbe
Show file tree
Hide file tree
Showing 9 changed files with 437 additions and 11 deletions.
51 changes: 51 additions & 0 deletions jerry-core/api/jerry.c
Original file line number Diff line number Diff line change
Expand Up @@ -3373,6 +3373,57 @@ jerry_free_property_descriptor_fields (const jerry_property_descriptor_t *prop_d
}
} /* jerry_free_property_descriptor_fields */

/**
* Hide the getter/setter functions of an accessor property, so the property is
* returned as a data property when the property descriptor is requested.
*
* Note:
* - only ordinary objects are supported
*
* @return true - if the operation is successful
* thrown error - otherwise
*/
jerry_value_t
jerry_hide_own_accessor_property (const jerry_value_t obj_val, /**< object value */
const jerry_value_t prop_name_val) /**< property name */
{
if (!ecma_is_value_object (obj_val)
|| !ecma_is_value_prop_name (prop_name_val))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
}

ecma_object_t *object_p = ecma_get_object_from_value (obj_val);

#if ENABLED (JERRY_BUILTIN_PROXY)
if (ECMA_OBJECT_IS_PROXY (object_p))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
}
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */

ecma_extended_property_ref_t ext_property_ref = { .property_ref.value_p = NULL, .property_p = NULL };
ecma_property_t property;

property = ecma_op_object_get_own_property (object_p,
ecma_get_prop_name_from_value (prop_name_val),
&ext_property_ref.property_ref,
ECMA_PROPERTY_GET_EXT_REFERENCE);

if (property == ECMA_PROPERTY_TYPE_NOT_FOUND || property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP)
{
return jerry_throw (ecma_raise_reference_error (ECMA_ERR_MSG ("Property not found")));
}

if (ECMA_PROPERTY_GET_TYPE (property) != ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
{
return jerry_throw (ecma_raise_reference_error (ECMA_ERR_MSG ("Property is not accessor property")));
}

*ext_property_ref.property_p |= ECMA_PROPERTY_FLAG_HIDDEN_ACCESSOR;
return ECMA_VALUE_TRUE;
} /* jerry_hide_own_accessor_property */

/**
* Invoke function specified by a function value
*
Expand Down
7 changes: 6 additions & 1 deletion jerry-core/ecma/base/ecma-globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,11 @@ typedef enum
#define ECMA_PROPERTY_ENUMERABLE_WRITABLE \
(ECMA_PROPERTY_FLAG_ENUMERABLE | ECMA_PROPERTY_FLAG_WRITABLE)

/**
* Property flag named accessor which is returned as data property.
*/
#define ECMA_PROPERTY_FLAG_HIDDEN_ACCESSOR ECMA_PROPERTY_FLAG_WRITABLE

/**
* No attributes can be changed for this property.
*/
Expand Down Expand Up @@ -1182,6 +1187,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_HIDDEN_ACCESSOR = (1 << 10), /** Is hidden accessor */
} ecma_property_descriptor_status_flags_t;

/**
Expand All @@ -1196,7 +1202,6 @@ typedef enum
*/
typedef struct
{

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

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_HIDDEN_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_HIDDEN_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_HIDDEN_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_HIDDEN_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
83 changes: 76 additions & 7 deletions jerry-core/ecma/operations/ecma-objects-general.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,15 +504,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_PROPERTY_TYPE_NAMEDACCESSOR)
Expand Down Expand Up @@ -549,6 +543,81 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob
prop_flags = (ecma_property_t) (prop_flags | property_desc_type);
*(ext_property_ref.property_p) = prop_flags;
}
else
{
/* Property is non-configurable. */
if (current_property_type != ECMA_PROPERTY_TYPE_NAMEDACCESSOR
|| !(current_prop & ECMA_PROPERTY_FLAG_HIDDEN_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_PROPERTY_TYPE_NAMEDDATA)
Expand Down
10 changes: 7 additions & 3 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 @@ -1892,7 +1892,6 @@ ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the ob
}
else
{

ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (property_ref.value_p);
prop_desc_p->flags |= (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED);

Expand All @@ -1915,6 +1914,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_HIDDEN_ACCESSOR)
{
prop_desc_p->flags |= ECMA_PROP_IS_HIDDEN_ACCESSOR;
}
}

return ECMA_VALUE_TRUE;
Expand Down
1 change: 1 addition & 0 deletions jerry-core/include/jerryscript-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@ bool jerry_get_own_property_descriptor (const jerry_value_t obj_val,
const jerry_value_t prop_name_val,
jerry_property_descriptor_t *prop_desc_p);
void jerry_free_property_descriptor_fields (const jerry_property_descriptor_t *prop_desc_p);
jerry_value_t jerry_hide_own_accessor_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val);

jerry_value_t jerry_call_function (const jerry_value_t func_obj_val, const jerry_value_t this_val,
const jerry_value_t args_p[], jerry_size_t args_count);
Expand Down
Loading

0 comments on commit 8e29bbe

Please sign in to comment.