diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c index ad7423f68..f62144f73 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c @@ -284,7 +284,7 @@ ecma_builtin_object_prototype_dispatch_routine (uint16_t builtin_routine_id, /** } #endif /* ENABLED (JERRY_ESNEXT)*/ - ecma_string_t *prop_name_p = ecma_op_to_prop_name (arguments_list_p[0]); + ecma_string_t *prop_name_p = ecma_op_to_property_key (arguments_list_p[0]); if (prop_name_p == NULL) { diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object.c b/jerry-core/ecma/builtin-objects/ecma-builtin-object.c index 0da291082..6035255c3 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object.c @@ -1213,7 +1213,7 @@ ecma_builtin_object_dispatch_routine (uint16_t builtin_routine_id, /**< built-in if (builtin_routine_id == ECMA_OBJECT_ROUTINE_DEFINE_PROPERTY) { - ecma_string_t *prop_name_p = ecma_op_to_prop_name (arg2); + ecma_string_t *prop_name_p = ecma_op_to_property_key (arg2); if (prop_name_p == NULL) { @@ -1275,7 +1275,7 @@ ecma_builtin_object_dispatch_routine (uint16_t builtin_routine_id, /**< built-in } case ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTOR: { - ecma_string_t *prop_name_p = ecma_op_to_prop_name (arg2); + ecma_string_t *prop_name_p = ecma_op_to_property_key (arg2); if (prop_name_p == NULL) { diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c index af55073fc..b71bc0c86 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c @@ -96,8 +96,8 @@ ecma_builtin_reflect_dispatch_routine (uint16_t builtin_routine_id, /**< built-i } /* 2. */ - ecma_string_t *name_str_p = ecma_op_to_prop_name (((arguments_number > 1) ? arguments_list[1] - : ECMA_VALUE_UNDEFINED)); + ecma_string_t *name_str_p = ecma_op_to_property_key (((arguments_number > 1) ? arguments_list[1] + : ECMA_VALUE_UNDEFINED)); /* 3. */ if (name_str_p == NULL) @@ -262,7 +262,7 @@ ecma_builtin_reflect_dispatch_routine (uint16_t builtin_routine_id, /**< built-i case ECMA_REFLECT_OBJECT_DEFINE_PROPERTY: { ecma_object_t *obj_p = ecma_get_object_from_value (arguments_list[0]); - ecma_string_t *name_str_p = ecma_op_to_prop_name (arguments_list[1]); + ecma_string_t *name_str_p = ecma_op_to_property_key (arguments_list[1]); if (name_str_p == NULL) { @@ -297,7 +297,7 @@ ecma_builtin_reflect_dispatch_routine (uint16_t builtin_routine_id, /**< built-i case ECMA_REFLECT_OBJECT_GET_OWN_PROPERTY_DESCRIPTOR: { ecma_object_t *obj_p = ecma_get_object_from_value (arguments_list[0]); - ecma_string_t *name_str_p = ecma_op_to_prop_name (arguments_list[1]); + ecma_string_t *name_str_p = ecma_op_to_property_key (arguments_list[1]); if (name_str_p == NULL) { diff --git a/jerry-core/ecma/operations/ecma-conversion.c b/jerry-core/ecma/operations/ecma-conversion.c index 7906f90ba..bd8693b3d 100644 --- a/jerry-core/ecma/operations/ecma-conversion.c +++ b/jerry-core/ecma/operations/ecma-conversion.c @@ -489,27 +489,51 @@ ecma_op_to_string (ecma_value_t value) /**< ecma value */ } /* ecma_op_to_string */ /** - * ToPropertyName operation. + * ToPropertyKey operation. + * + * See also: + * ECMA 262 v6, 7.1.14 + * ECMA 262 v10, 7.1.14 + * ECMA 262 v11, 7.1.19 * * @return NULL - if the conversion fails * ecma-string - otherwise */ ecma_string_t * -ecma_op_to_prop_name (ecma_value_t value) /**< ecma value */ +ecma_op_to_property_key (ecma_value_t value) /**< ecma value */ { - ecma_check_value_type_is_spec_defined (value); + /* Fast path for strings and symbols */ + if (JERRY_LIKELY (ecma_is_value_prop_name (value))) + { + ecma_string_t *key_p = ecma_get_prop_name_from_value (value); + ecma_ref_ecma_string (key_p); + return key_p; + } #if ENABLED (JERRY_ESNEXT) - if (ecma_is_value_symbol (value)) + ecma_value_t key = ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_STRING); + + if (ECMA_IS_VALUE_ERROR (key)) { - ecma_string_t *symbol_p = ecma_get_symbol_from_value (value); - ecma_ref_ecma_string (symbol_p); + return NULL; + } + + if (ecma_is_value_symbol (key)) + { + ecma_string_t *symbol_p = ecma_get_symbol_from_value (key); return symbol_p; } -#endif /* ENABLED (JERRY_ESNEXT) */ + + ecma_string_t *result = ecma_op_to_string (key); + ecma_free_value (key); + + return result; +#else /* !ENABLED (JERRY_ESNEXT) */ + ecma_check_value_type_is_spec_defined (value); return ecma_op_to_string (value); -} /* ecma_op_to_prop_name */ +#endif /* ENABLED (JERRY_ESNEXT) */ +} /* ecma_op_to_property_key */ /** * ToObject operation. diff --git a/jerry-core/ecma/operations/ecma-conversion.h b/jerry-core/ecma/operations/ecma-conversion.h index 4dc612a60..be1a25d19 100644 --- a/jerry-core/ecma/operations/ecma-conversion.h +++ b/jerry-core/ecma/operations/ecma-conversion.h @@ -47,7 +47,7 @@ bool ecma_op_to_boolean (ecma_value_t value); ecma_value_t ecma_op_to_number (ecma_value_t value); ecma_value_t ecma_get_number (ecma_value_t value, ecma_number_t *number_p); ecma_string_t *ecma_op_to_string (ecma_value_t value); -ecma_string_t *ecma_op_to_prop_name (ecma_value_t value); +ecma_string_t *ecma_op_to_property_key (ecma_value_t value); ecma_value_t ecma_op_to_object (ecma_value_t value); ecma_value_t ecma_op_to_integer (ecma_value_t value, ecma_number_t *number_p); ecma_value_t ecma_op_to_length (ecma_value_t value, uint32_t *length); diff --git a/jerry-core/vm/opcodes-ecma-relational-equality.c b/jerry-core/vm/opcodes-ecma-relational-equality.c index ffc2344fc..328c89884 100644 --- a/jerry-core/vm/opcodes-ecma-relational-equality.c +++ b/jerry-core/vm/opcodes-ecma-relational-equality.c @@ -159,7 +159,7 @@ opfunc_in (ecma_value_t left_value, /**< left value */ return ecma_raise_type_error (ECMA_ERR_MSG ("Expected an object in 'in' check.")); } - ecma_string_t *property_name_p = ecma_op_to_prop_name (left_value); + ecma_string_t *property_name_p = ecma_op_to_property_key (left_value); if (JERRY_UNLIKELY (property_name_p == NULL)) { diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 7cbbc3d4e..ef315b745 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -262,7 +262,7 @@ vm_op_delete_prop (ecma_value_t object, /**< base object */ } JERRY_ASSERT (check_coercible == ECMA_VALUE_EMPTY); - ecma_string_t *name_string_p = ecma_op_to_prop_name (property); + ecma_string_t *name_string_p = ecma_op_to_property_key (property); if (JERRY_UNLIKELY (name_string_p == NULL)) { @@ -1398,7 +1398,7 @@ opfunc_form_super_reference (ecma_value_t **vm_stack_top_p, /**< current vm stac } ecma_object_t *parent_p = ecma_get_object_from_value (parent); - ecma_string_t *prop_name_p = ecma_op_to_prop_name (prop_name); + ecma_string_t *prop_name_p = ecma_op_to_property_key (prop_name); if (prop_name_p == NULL) { @@ -1448,7 +1448,7 @@ opfunc_assign_super_reference (ecma_value_t **vm_stack_top_p, /**< vm stack top } ecma_object_t *base_obj_p = ecma_get_object_from_value (base_obj); - ecma_string_t *prop_name_p = ecma_op_to_prop_name (stack_top_p[-2]); + ecma_string_t *prop_name_p = ecma_op_to_property_key (stack_top_p[-2]); if (prop_name_p == NULL) { diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 0b7b43cce..dff18ca39 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -132,7 +132,7 @@ vm_op_get_value (ecma_value_t object, /**< base object */ return error_value; } - ecma_string_t *property_name_p = ecma_op_to_prop_name (property); + ecma_string_t *property_name_p = ecma_op_to_property_key (property); if (property_name_p == NULL) { @@ -1816,7 +1816,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT ((opcode_data >> VM_OC_NON_STATIC_SHIFT) <= 0x1); - ecma_string_t *prop_name_p = ecma_op_to_prop_name (right_value); + ecma_string_t *prop_name_p = ecma_op_to_property_key (right_value); if (JERRY_UNLIKELY (prop_name_p == NULL)) { @@ -1849,7 +1849,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { JERRY_ASSERT ((opcode_data >> VM_OC_NON_STATIC_SHIFT) <= 0x1); - ecma_string_t *prop_name_p = ecma_op_to_prop_name (left_value); + ecma_string_t *prop_name_p = ecma_op_to_property_key (left_value); if (JERRY_UNLIKELY (prop_name_p == NULL)) { @@ -2029,7 +2029,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ prop_name_value = stack_top_p[-2]; } - ecma_string_t *prop_name_p = ecma_op_to_prop_name (prop_name_value); + ecma_string_t *prop_name_p = ecma_op_to_property_key (prop_name_value); if (JERRY_UNLIKELY (prop_name_p == NULL)) { diff --git a/tests/jerry/es.next/to-property-key.js b/tests/jerry/es.next/to-property-key.js new file mode 100644 index 000000000..4b30b3f51 --- /dev/null +++ b/tests/jerry/es.next/to-property-key.js @@ -0,0 +1,126 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* Test if the ToPropertyKey operation calls the @@ToPrimitive symbol */ + +var obj_A = {}; +var sym = Symbol(); + +var toprimitive_called = 0; + +var wrap = { + [Symbol.toPrimitive]: function() { + toprimitive_called++; + return sym; + } +}; + +/* .hasOwnProperty calls the ToPropertyKey operation */ +assert (obj_A.hasOwnProperty (wrap) === false); +assert (toprimitive_called === 1); + +/* "in" operator calls the ToPropertyKey operation */ +assert ((wrap in obj_A) === false); +assert (toprimitive_called === 2); + +obj_A[sym] = 0; + +/* .hasOwnProperty calls the ToPropertyKey operation */ +assert (obj_A.hasOwnProperty (wrap) === true); +assert (toprimitive_called === 3); + +/* "in" operator calls the ToPropertyKey operation */ +assert ((wrap in obj_A) === true); +assert (toprimitive_called === 4); + + +var obj_B = {}; + +/* .hasOwnProperty calls the ToPropertyKey operation */ +assert (obj_B.hasOwnProperty (wrap) === false); +assert (toprimitive_called === 5); + +/* Object.defineProperty calls the ToPropertyKey operation */ +Object.defineProperty (obj_B, wrap, { + value: -1, + enumerable: false, + configurable: true, + writable: true +}); +assert (toprimitive_called === 6); + +assert (obj_B[sym] === -1); + +/* Object.getOwnPropertyDescriptor calls the ToPropertyKey operation */ +var desc = Object.getOwnPropertyDescriptor (obj_B, wrap); +assert (toprimitive_called === 7); + +assert (desc.value === -1); +assert (desc.enumerable === false); +assert (desc.configurable === true); +assert (desc.writable === true); + +/* Reflect.get calls the ToPropertyKey operation */ +assert (Reflect.get (obj_B, wrap) === -1); +assert (toprimitive_called === 8); + +/* Reflect.deleteProperty calls the ToPropertyKey operation */ +assert (Reflect.deleteProperty (obj_B, wrap) === true); +assert (toprimitive_called === 9); + +/* Reflect.has calls the ToPropertyKey operation */ +assert (Reflect.has (obj_B, wrap) === false); +assert (toprimitive_called === 10); + +/* Reflect.defineProperty calls the ToPropertyKey operation */ +Reflect.defineProperty (obj_B, wrap, { + value: 50, + enumerable: false, + configurable: true, + writable: true +}); + +assert (toprimitive_called === 11); + +/* Reflect.getOwnPropertyDescriptor calls the ToPropertyKey operation */ +var desc_B = Reflect.getOwnPropertyDescriptor (obj_B, wrap); +assert (toprimitive_called === 12); + +assert (desc_B.value === 50); +assert (desc_B.enumerable === false); +assert (desc_B.configurable === true); +assert (desc_B.writable === true); + +/* Delete calls the ToPropertyKey operation */ +delete obj_B[wrap]; +assert (toprimitive_called === 13); + +/* Get calls the ToPropertyKey operation */ +assert (obj_B[wrap] === undefined); +assert (toprimitive_called === 14); + +/* Computed property calls the ToPropertyKey operation */ +var obj_C = { + [wrap]: function() { return 100; } +}; +assert (toprimitive_called === 15); +assert (obj_C[sym]() === 100); + +/* Setter/Getter will each call the ToPropertyKey operation */ +var obj_D = { + get [wrap] () { return 150; }, + set [wrap] (value) { } +}; +assert (toprimitive_called === 17); +assert (obj_D[sym] === 150); diff --git a/tests/test262-es6-excludelist.xml b/tests/test262-es6-excludelist.xml index c4fa694b0..95031e99c 100644 --- a/tests/test262-es6-excludelist.xml +++ b/tests/test262-es6-excludelist.xml @@ -61,12 +61,6 @@ - - - - - -