Skip to content

Commit 8e29bbe

Browse files
committed
Disguise accessor properties as data properties
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg [email protected]
1 parent 33c0413 commit 8e29bbe

File tree

9 files changed

+437
-11
lines changed

9 files changed

+437
-11
lines changed

jerry-core/api/jerry.c

+51
Original file line numberDiff line numberDiff line change
@@ -3373,6 +3373,57 @@ jerry_free_property_descriptor_fields (const jerry_property_descriptor_t *prop_d
33733373
}
33743374
} /* jerry_free_property_descriptor_fields */
33753375

3376+
/**
3377+
* Hide the getter/setter functions of an accessor property, so the property is
3378+
* returned as a data property when the property descriptor is requested.
3379+
*
3380+
* Note:
3381+
* - only ordinary objects are supported
3382+
*
3383+
* @return true - if the operation is successful
3384+
* thrown error - otherwise
3385+
*/
3386+
jerry_value_t
3387+
jerry_hide_own_accessor_property (const jerry_value_t obj_val, /**< object value */
3388+
const jerry_value_t prop_name_val) /**< property name */
3389+
{
3390+
if (!ecma_is_value_object (obj_val)
3391+
|| !ecma_is_value_prop_name (prop_name_val))
3392+
{
3393+
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
3394+
}
3395+
3396+
ecma_object_t *object_p = ecma_get_object_from_value (obj_val);
3397+
3398+
#if ENABLED (JERRY_BUILTIN_PROXY)
3399+
if (ECMA_OBJECT_IS_PROXY (object_p))
3400+
{
3401+
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
3402+
}
3403+
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
3404+
3405+
ecma_extended_property_ref_t ext_property_ref = { .property_ref.value_p = NULL, .property_p = NULL };
3406+
ecma_property_t property;
3407+
3408+
property = ecma_op_object_get_own_property (object_p,
3409+
ecma_get_prop_name_from_value (prop_name_val),
3410+
&ext_property_ref.property_ref,
3411+
ECMA_PROPERTY_GET_EXT_REFERENCE);
3412+
3413+
if (property == ECMA_PROPERTY_TYPE_NOT_FOUND || property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP)
3414+
{
3415+
return jerry_throw (ecma_raise_reference_error (ECMA_ERR_MSG ("Property not found")));
3416+
}
3417+
3418+
if (ECMA_PROPERTY_GET_TYPE (property) != ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
3419+
{
3420+
return jerry_throw (ecma_raise_reference_error (ECMA_ERR_MSG ("Property is not accessor property")));
3421+
}
3422+
3423+
*ext_property_ref.property_p |= ECMA_PROPERTY_FLAG_HIDDEN_ACCESSOR;
3424+
return ECMA_VALUE_TRUE;
3425+
} /* jerry_hide_own_accessor_property */
3426+
33763427
/**
33773428
* Invoke function specified by a function value
33783429
*

jerry-core/ecma/base/ecma-globals.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,11 @@ typedef enum
443443
#define ECMA_PROPERTY_ENUMERABLE_WRITABLE \
444444
(ECMA_PROPERTY_FLAG_ENUMERABLE | ECMA_PROPERTY_FLAG_WRITABLE)
445445

446+
/**
447+
* Property flag named accessor which is returned as data property.
448+
*/
449+
#define ECMA_PROPERTY_FLAG_HIDDEN_ACCESSOR ECMA_PROPERTY_FLAG_WRITABLE
450+
446451
/**
447452
* No attributes can be changed for this property.
448453
*/
@@ -1182,6 +1187,7 @@ typedef enum
11821187
ECMA_PROP_IS_CONFIGURABLE_DEFINED = (1 << 7), /** Is [[Configurable]] defined? */
11831188
ECMA_PROP_IS_ENUMERABLE_DEFINED = (1 << 8), /** Is [[Enumerable]] defined? */
11841189
ECMA_PROP_IS_WRITABLE_DEFINED = (1 << 9), /** Is [[Writable]] defined? */
1190+
ECMA_PROP_IS_HIDDEN_ACCESSOR = (1 << 10), /** Is hidden accessor */
11851191
} ecma_property_descriptor_status_flags_t;
11861192

11871193
/**
@@ -1196,7 +1202,6 @@ typedef enum
11961202
*/
11971203
typedef struct
11981204
{
1199-
12001205
/** any combination of ecma_property_descriptor_status_flags_t bits */
12011206
uint16_t flags;
12021207

jerry-core/ecma/builtin-objects/ecma-builtin-object.c

+25
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,17 @@ ecma_builtin_object_object_get_own_property_descriptor (ecma_object_t *obj_p, /*
725725

726726
if (ecma_is_value_true (status))
727727
{
728+
if (JERRY_UNLIKELY (prop_desc.flags & ECMA_PROP_IS_HIDDEN_ACCESSOR))
729+
{
730+
status = ecma_op_to_data_property (obj_p, &prop_desc);
731+
732+
if (ECMA_IS_VALUE_ERROR (status))
733+
{
734+
ecma_free_property_descriptor (&prop_desc);
735+
return status;
736+
}
737+
}
738+
728739
/* 4. */
729740
ecma_object_t *desc_obj_p = ecma_op_from_property_descriptor (&prop_desc);
730741

@@ -786,6 +797,20 @@ ecma_builtin_object_object_get_own_property_descriptors (ecma_object_t *obj_p) /
786797

787798
if (ecma_is_value_true (status))
788799
{
800+
if (JERRY_UNLIKELY (prop_desc.flags & ECMA_PROP_IS_HIDDEN_ACCESSOR))
801+
{
802+
status = ecma_op_to_data_property (obj_p, &prop_desc);
803+
804+
if (ECMA_IS_VALUE_ERROR (status))
805+
{
806+
ecma_free_property_descriptor (&prop_desc);
807+
ecma_deref_object (descriptors_p);
808+
ecma_collection_free (prop_names_p);
809+
810+
return status;
811+
}
812+
}
813+
789814
/* 4.b */
790815
ecma_object_t *desc_obj_p = ecma_op_from_property_descriptor (&prop_desc);
791816
/* 4.c */

jerry-core/ecma/operations/ecma-conversion.c

+44
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,50 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */
908908
return ret_value;
909909
} /* ecma_op_to_property_descriptor */
910910

911+
/**
912+
* Convert accessor to data property.
913+
*
914+
* @return ECMA_VALUE_EMPTY - if the opertation is successful
915+
* error - otherwise
916+
*/
917+
ecma_value_t
918+
ecma_op_to_data_property (ecma_object_t *object_p, /**< base object */
919+
ecma_property_descriptor_t *prop_desc_p) /**< [in/out] property descriptor */
920+
{
921+
JERRY_ASSERT (prop_desc_p->flags & ECMA_PROP_IS_HIDDEN_ACCESSOR);
922+
923+
ecma_value_t result = ECMA_VALUE_UNDEFINED;
924+
uint16_t flags = prop_desc_p->flags;
925+
926+
if ((flags & ECMA_PROP_IS_GET_DEFINED) && prop_desc_p->get_p != NULL)
927+
{
928+
result = ecma_op_function_call (prop_desc_p->get_p, ecma_make_object_value (object_p), NULL, 0);
929+
930+
if (ECMA_IS_VALUE_ERROR (result))
931+
{
932+
return result;
933+
}
934+
935+
ecma_deref_object (prop_desc_p->get_p);
936+
prop_desc_p->get_p = NULL;
937+
}
938+
939+
if ((flags & ECMA_PROP_IS_SET_DEFINED) && prop_desc_p->set_p != NULL)
940+
{
941+
ecma_deref_object (prop_desc_p->set_p);
942+
prop_desc_p->set_p = NULL;
943+
944+
flags |= ECMA_PROP_IS_WRITABLE;
945+
}
946+
947+
flags |= ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_VALUE_DEFINED;
948+
flags &= (uint16_t) ~(ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED | ECMA_PROP_IS_HIDDEN_ACCESSOR);
949+
950+
prop_desc_p->value = result;
951+
prop_desc_p->flags = flags;
952+
return ECMA_VALUE_EMPTY;
953+
} /* ecma_op_to_data_property */
954+
911955
/**
912956
* IsInteger operation.
913957
*

jerry-core/ecma/operations/ecma-conversion.h

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ ecma_collection_t *ecma_op_create_list_from_array_like (ecma_value_t arr, bool p
7272

7373
ecma_object_t *ecma_op_from_property_descriptor (const ecma_property_descriptor_t *src_prop_desc_p);
7474
ecma_value_t ecma_op_to_property_descriptor (ecma_value_t obj_value, ecma_property_descriptor_t *out_prop_desc_p);
75+
ecma_value_t ecma_op_to_data_property (ecma_object_t *object_p, ecma_property_descriptor_t *prop_desc_p);
7576

7677
/**
7778
* @}

jerry-core/ecma/operations/ecma-objects-general.c

+76-7
Original file line numberDiff line numberDiff line change
@@ -504,15 +504,9 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob
504504
}
505505
}
506506
}
507-
else
507+
else if (is_current_configurable)
508508
{
509509
/* 9. */
510-
if (!is_current_configurable)
511-
{
512-
/* a. */
513-
return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW);
514-
}
515-
516510
ecma_property_value_t *value_p = ext_property_ref.property_ref.value_p;
517511

518512
if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDACCESSOR)
@@ -549,6 +543,81 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob
549543
prop_flags = (ecma_property_t) (prop_flags | property_desc_type);
550544
*(ext_property_ref.property_p) = prop_flags;
551545
}
546+
else
547+
{
548+
/* Property is non-configurable. */
549+
if (current_property_type != ECMA_PROPERTY_TYPE_NAMEDACCESSOR
550+
|| !(current_prop & ECMA_PROPERTY_FLAG_HIDDEN_ACCESSOR))
551+
{
552+
/* a. */
553+
return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW);
554+
}
555+
556+
/* Non-standard extension. */
557+
ecma_getter_setter_pointers_t *getter_setter_pair_p;
558+
getter_setter_pair_p = ecma_get_named_accessor_property (ext_property_ref.property_ref.value_p);
559+
560+
if (getter_setter_pair_p->setter_cp == JMEM_CP_NULL)
561+
{
562+
const uint16_t mask = ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_WRITABLE;
563+
564+
if ((property_desc_p->flags & mask) == mask)
565+
{
566+
return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW);
567+
}
568+
569+
if (!(property_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED))
570+
{
571+
return ECMA_VALUE_TRUE;
572+
}
573+
574+
ecma_value_t result = ECMA_VALUE_UNDEFINED;
575+
576+
if (getter_setter_pair_p->getter_cp != JMEM_CP_NULL)
577+
{
578+
ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, getter_setter_pair_p->getter_cp);
579+
result = ecma_op_function_call (getter_p, ecma_make_object_value (object_p), NULL, 0);
580+
581+
if (ECMA_IS_VALUE_ERROR (result))
582+
{
583+
return result;
584+
}
585+
}
586+
587+
bool same_value = ecma_op_same_value (property_desc_p->value, result);
588+
ecma_free_value (result);
589+
590+
if (!same_value)
591+
{
592+
return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW);
593+
}
594+
return ECMA_VALUE_TRUE;
595+
}
596+
597+
if (property_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED)
598+
{
599+
ecma_object_t *setter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, getter_setter_pair_p->setter_cp);
600+
601+
ecma_value_t result;
602+
result = ecma_op_function_call (setter_p, ecma_make_object_value (object_p), &property_desc_p->value, 1);
603+
604+
if (ECMA_IS_VALUE_ERROR (result))
605+
{
606+
return result;
607+
}
608+
609+
ecma_free_value (result);
610+
}
611+
612+
/* Because the property is non-configurable, it cannot be modified. */
613+
if ((property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
614+
&& !(property_desc_p->flags & ECMA_PROP_IS_WRITABLE))
615+
{
616+
getter_setter_pair_p->setter_cp = JMEM_CP_NULL;
617+
}
618+
619+
return ECMA_VALUE_TRUE;
620+
}
552621

553622
/* 12. */
554623
if (property_desc_type == ECMA_PROPERTY_TYPE_NAMEDDATA)

jerry-core/ecma/operations/ecma-objects.c

+7-3
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@
6565
* See also:
6666
* ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
6767
*
68-
* @return pointer to a property - if it exists,
69-
* NULL (i.e. ecma-undefined) - otherwise.
68+
* @return property descriptor - if it exists,
69+
* ECMA_PROPERTY_TYPE_NOT_FOUND / ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP - otherwise.
7070
*/
7171
ecma_property_t
7272
ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */
@@ -1892,7 +1892,6 @@ ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the ob
18921892
}
18931893
else
18941894
{
1895-
18961895
ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (property_ref.value_p);
18971896
prop_desc_p->flags |= (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED);
18981897

@@ -1915,6 +1914,11 @@ ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the ob
19151914
prop_desc_p->set_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->setter_cp);
19161915
ecma_ref_object (prop_desc_p->set_p);
19171916
}
1917+
1918+
if (property & ECMA_PROPERTY_FLAG_HIDDEN_ACCESSOR)
1919+
{
1920+
prop_desc_p->flags |= ECMA_PROP_IS_HIDDEN_ACCESSOR;
1921+
}
19181922
}
19191923

19201924
return ECMA_VALUE_TRUE;

jerry-core/include/jerryscript-core.h

+1
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,7 @@ bool jerry_get_own_property_descriptor (const jerry_value_t obj_val,
633633
const jerry_value_t prop_name_val,
634634
jerry_property_descriptor_t *prop_desc_p);
635635
void jerry_free_property_descriptor_fields (const jerry_property_descriptor_t *prop_desc_p);
636+
jerry_value_t jerry_hide_own_accessor_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val);
636637

637638
jerry_value_t jerry_call_function (const jerry_value_t func_obj_val, const jerry_value_t this_val,
638639
const jerry_value_t args_p[], jerry_size_t args_count);

0 commit comments

Comments
 (0)