diff --git a/jerry-core/config.h b/jerry-core/config.h index de97d24f4..2cb623047 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -99,6 +99,14 @@ # define JERRY_ES2015_BUILTIN_SET JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_SET) */ +#ifndef JERRY_ES2015_BUILTIN_WEAKMAP +# define JERRY_ES2015_BUILTIN_WEAKMAP JERRY_ES2015 +#endif /* !defined (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#ifndef JERRY_ES2015_BUILTIN_WEAKSET +# define JERRY_ES2015_BUILTIN_WEAKSET JERRY_ES2015 +#endif /* !defined (JERRY_ES2015_BUILTIN_WEAKSET) */ + #ifndef JERRY_ES2015_BUILTIN_PROMISE # define JERRY_ES2015_BUILTIN_PROMISE JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_PROMISE) */ @@ -540,6 +548,14 @@ || ((JERRY_ES2015_BUILTIN_SET != 0) && (JERRY_ES2015_BUILTIN_SET != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_SET macro." #endif +#if !defined (JERRY_ES2015_BUILTIN_WEAKMAP) \ +|| ((JERRY_ES2015_BUILTIN_WEAKMAP != 0) && (JERRY_ES2015_BUILTIN_WEAKMAP != 1)) +# error "Invalid value for JERRY_ES2015_BUILTIN_WEAKMAP macro." +#endif +#if !defined (JERRY_ES2015_BUILTIN_WEAKSET) \ +|| ((JERRY_ES2015_BUILTIN_WEAKSET != 0) && (JERRY_ES2015_BUILTIN_WEAKSET != 1)) +# error "Invalid value for JERRY_ES2015_BUILTIN_WEAKSET macro." +#endif #if !defined (JERRY_ES2015_BUILTIN_PROMISE) \ || ((JERRY_ES2015_BUILTIN_PROMISE != 0) && (JERRY_ES2015_BUILTIN_PROMISE != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_PROMISE macro." @@ -668,4 +684,14 @@ # error "Date does not support float32" #endif +/** + * Wrap container types into a single guard + */ +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) +# define JERRY_ES2015_BUILTIN_CONTAINER 1 +#else +# define JERRY_ES2015_BUILTIN_CONTAINER 0 +#endif + #endif /* !JERRYSCRIPT_CONFIG_H */ diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 64d52cffc..8ad33d1ee 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -292,15 +292,17 @@ ecma_gc_mark_promise_object (ecma_extended_object_t *ext_object_p) /**< extended #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) /** * Mark objects referenced by Map/Set built-in. */ static void ecma_gc_mark_container_object (ecma_object_t *object_p) /**< object */ { - ecma_map_object_t *map_object_p = (ecma_map_object_t *) object_p; - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + ecma_object_t *internal_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + map_object_p->u.class_prop.u.value); + ecma_extended_object_t *internal_ext_p = (ecma_extended_object_t *) internal_obj_p; ecma_gc_set_object_visited (internal_obj_p); @@ -325,24 +327,27 @@ ecma_gc_mark_container_object (ecma_object_t *object_p) /**< object */ ecma_gc_mark_properties ((ecma_property_pair_t *) prop_iter_p); - ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; - - for (uint32_t i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) + if ((internal_ext_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) == 0) { - ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); + ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; - if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR) + for (uint32_t i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { - jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; - ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp); + ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); - if (ECMA_STRING_GET_CONTAINER (prop_name_p) == ECMA_STRING_CONTAINER_MAP_KEY) + if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR) { - ecma_value_t key_arg = ((ecma_extended_string_t *) prop_name_p)->u.value; + jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; + ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp); - if (ecma_is_value_object (key_arg)) + if (ECMA_STRING_GET_CONTAINER (prop_name_p) == ECMA_STRING_CONTAINER_MAP_KEY) { - ecma_gc_set_object_visited (ecma_get_object_from_value (key_arg)); + ecma_value_t key_arg = ((ecma_extended_string_t *) prop_name_p)->u.value; + + if (ecma_is_value_object (key_arg)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (key_arg)); + } } } } @@ -352,7 +357,7 @@ ecma_gc_mark_container_object (ecma_object_t *object_p) /**< object */ } } /* ecma_gc_mark_container_object */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ /** * Mark objects as visited starting from specified object as root @@ -412,20 +417,24 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ break; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) #if ENABLED (JERRY_ES2015_BUILTIN_MAP) case LIT_MAGIC_STRING_MAP_UL: - { - ecma_gc_mark_container_object (object_p); - break; - } #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ #if ENABLED (JERRY_ES2015_BUILTIN_SET) case LIT_MAGIC_STRING_SET_UL: +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + case LIT_MAGIC_STRING_WEAKMAP_UL: +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + case LIT_MAGIC_STRING_WEAKSET_UL: +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ { ecma_gc_mark_container_object (object_p); break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ default: { break; @@ -669,11 +678,33 @@ ecma_gc_free_properties (ecma_object_t *object_p) /**< object */ ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; - /* Call the native's free callback. */ - if (JERRY_UNLIKELY (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC - && (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER))) + if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC) { - ecma_gc_free_native_pointer (property_p); + /* Call the native's free callback. */ + if (JERRY_UNLIKELY (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER)) + { + ecma_gc_free_native_pointer (property_p); + } +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + else if (JERRY_UNLIKELY (name_cp == LIT_INTERNAL_MAGIC_STRING_WEAK_REFS)) + { + ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + ECMA_PROPERTY_VALUE_PTR (property_p)->value); + for (uint32_t j = 0; j < refs_p->item_count; j++) + { + const ecma_value_t value = refs_p->buffer_p[j]; + if (!ecma_is_value_empty (value)) + { + ecma_object_t *container_p = ecma_get_object_from_value (value); + + ecma_op_container_remove_weak_entry (container_p, + ecma_make_object_value (object_p)); + } + } + + ecma_collection_destroy (refs_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ } if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED) @@ -831,18 +862,67 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ break; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) #if ENABLED (JERRY_ES2015_BUILTIN_MAP) case LIT_MAGIC_STRING_MAP_UL: #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ #if ENABLED (JERRY_ES2015_BUILTIN_SET) case LIT_MAGIC_STRING_SET_UL: #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + case LIT_MAGIC_STRING_WEAKMAP_UL: +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + case LIT_MAGIC_STRING_WEAKSET_UL: +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ { - ext_object_size = sizeof (ecma_map_object_t); break; } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ + case LIT_INTERNAL_MAGIC_STRING_CONTAINER: + { +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + ecma_extended_object_t *container_p = (ecma_extended_object_t *) object_p; + + if (container_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) + { + jmem_cpointer_t prop_iter_cp = container_p->object.u1.property_list_cp; + while (prop_iter_cp != JMEM_CP_NULL) + { + ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); + JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); + + /* Both cannot be deleted. */ + JERRY_ASSERT (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED + || prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED); + + ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; + + for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) + { + ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); + + if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR) + { + jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; + ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp); + + if (JERRY_LIKELY (ECMA_STRING_GET_CONTAINER (prop_name_p) == ECMA_STRING_CONTAINER_MAP_KEY)) + { + ecma_value_t key_arg = ((ecma_extended_string_t *) prop_name_p)->u.value; + ecma_object_t *key_object_p = ecma_get_object_from_value (key_arg); + + ecma_op_container_unref_weak (key_object_p, ecma_make_object_value (object_p)); + } + } + } + + prop_iter_cp = prop_iter_p->next_property_cp; + } + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) case LIT_MAGIC_STRING_DATAVIEW_UL: { diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 6dda10099..7119e0a7e 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -961,16 +961,16 @@ typedef struct #endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) /** - * Description of Map/Set objects. + * Flags for container objects */ -typedef struct +typedef enum { - ecma_extended_object_t header; /**< header part */ - uint32_t size; /**< size of the map object */ -} ecma_map_object_t; -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ + ECMA_CONTAINER_FLAGS_EMPTY = (0), /** empty flags */ + ECMA_CONTAINER_FLAGS_WEAK = (1 << 0) /** container object is weak */ +} ecma_container_flags_t; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ typedef enum { diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h index 8ad00c038..ba8c9a5aa 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h @@ -219,6 +219,20 @@ OBJECT_VALUE (LIT_MAGIC_STRING_SET_UL, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) +/* ECMA-262 v6, 23.1.1.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_WEAKMAP_UL, + ECMA_BUILTIN_ID_WEAKMAP, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) +/* ECMA-262 v6, 23.1.1.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_WEAKSET_UL, + ECMA_BUILTIN_ID_WEAKSET, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + #if ENABLED (JERRY_ES2015) /* ECMA-262 v6, 19.4.1.1 */ OBJECT_VALUE (LIT_MAGIC_STRING_SYMBOL_UL, diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c index 31266bd7a..96145f201 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c @@ -96,7 +96,7 @@ static ecma_value_t ecma_builtin_map_prototype_object_get (ecma_value_t this_arg, /**< this argument */ ecma_value_t key_arg) /**< key argument */ { - return ecma_op_container_get (this_arg, key_arg); + return ecma_op_container_get (this_arg, key_arg, LIT_MAGIC_STRING_MAP_UL); } /* ecma_builtin_map_prototype_object_get */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.c new file mode 100644 index 000000000..b672f73e3 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.c @@ -0,0 +1,108 @@ +/* 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. + */ + +#include "ecma-container-object.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-weakmap-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID weakmap_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup weakmap ECMA WeakMap object built-in + * @{ + */ + +/** + * The WeakMap.prototype object's 'delete' routine + * + * See also: + * ECMA-262 v6, 23.3.3.2 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakmap_prototype_object_delete (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + return ecma_op_container_delete_weak (this_arg, key_arg, LIT_MAGIC_STRING_WEAKMAP_UL); +} /* ecma_builtin_weakmap_prototype_object_delete */ + +/** + * The WeakMap.prototype object's 'get' routine + * + * See also: + * ECMA-262 v6, 23.3.3.3 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakmap_prototype_object_get (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + return ecma_op_container_get (this_arg, key_arg, LIT_MAGIC_STRING_WEAKMAP_UL); +} /* ecma_builtin_weakmap_prototype_object_get */ + +/** + * The WeakMap.prototype object's 'has' routine + * + * See also: + * ECMA-262 v6, 23.3.3.4 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakmap_prototype_object_has (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + return ecma_op_container_has (this_arg, key_arg, LIT_MAGIC_STRING_WEAKMAP_UL); +} /* ecma_builtin_weakmap_prototype_object_has */ + +/** + * The WeakMap.prototype object's 'set' routine + * + * See also: + * ECMA-262 v6, 23.3.3.5 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakmap_prototype_object_set (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg, /**< key argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_set_weak (this_arg, key_arg, value_arg, LIT_MAGIC_STRING_WEAKMAP_UL); +} /* ecma_builtin_weakmap_prototype_object_set */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.inc.h new file mode 100644 index 000000000..a2db2edf0 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap-prototype.inc.h @@ -0,0 +1,46 @@ +/* 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. + */ + +/* + * WeakMap.prototype built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.3.3.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_WEAKMAP, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) + +/* ECMA-262 v6, 23.3.3.6 */ +STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_WEAKMAP_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_MAGIC_STRING_DELETE, ecma_builtin_weakmap_prototype_object_delete, 1, 1) +ROUTINE (LIT_MAGIC_STRING_GET, ecma_builtin_weakmap_prototype_object_get, 1, 1) +ROUTINE (LIT_MAGIC_STRING_HAS, ecma_builtin_weakmap_prototype_object_has, 1, 1) +ROUTINE (LIT_MAGIC_STRING_SET, ecma_builtin_weakmap_prototype_object_set, 2, 2) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.c b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.c new file mode 100644 index 000000000..8a94940bd --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.c @@ -0,0 +1,74 @@ +/* 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. + */ + +#include "ecma-builtins.h" +#include "ecma-exceptions.h" +#include "ecma-container-object.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-weakmap.inc.h" +#define BUILTIN_UNDERSCORED_ID weakmap +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup weakmap ECMA WeakMap object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in WeakMap object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_weakmap_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor WeakMap requires 'new'.")); +} /* ecma_builtin_weakmap_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in WeakMap object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_weakmap_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_op_container_create (arguments_list_p, + arguments_list_len, + LIT_MAGIC_STRING_WEAKMAP_UL, + ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE); +} /* ecma_builtin_weakmap_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.inc.h new file mode 100644 index 000000000..5abc2e36a --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakmap.inc.h @@ -0,0 +1,47 @@ +/* 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. + */ + +/* + * WeakMap built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + +/* Number properties: + * (property name, number value, writable, enumerable, configurable) */ + +/* ECMA-262 v6, 23.3.2 */ +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 0, + ECMA_PROPERTY_FIXED) + +/* ECMA-262 v6, 23.1 */ +STRING_VALUE (LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_WEAKMAP_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.3.2.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE, + ECMA_PROPERTY_FIXED) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.c new file mode 100644 index 000000000..a3a66c813 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.c @@ -0,0 +1,91 @@ +/* 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. + */ + +#include "ecma-container-object.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-weakset-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID weakset_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup weakset ECMA WeakSet object built-in + * @{ + */ + +/** + * The WeakSet.prototype object's 'add' routine + * + * See also: + * ECMA-262 v6, 23.4.3.1 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakset_prototype_object_add (ecma_value_t this_arg, /**< this argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_set_weak (this_arg, value_arg, ECMA_VALUE_UNDEFINED, LIT_MAGIC_STRING_WEAKSET_UL); +} /* ecma_builtin_weakset_prototype_object_add */ + +/** + * The WeakSet.prototype object's 'delete' routine + * + * See also: + * ECMA-262 v6, 23.4.3.3 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakset_prototype_object_delete (ecma_value_t this_arg, /**< this argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_delete_weak (this_arg, value_arg, LIT_MAGIC_STRING_WEAKSET_UL); +} /* ecma_builtin_weakset_prototype_object_delete */ + +/** + * The WeakSet.prototype object's 'has' routine + * + * See also: + * ECMA-262 v6, 23.4.3.4 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_weakset_prototype_object_has (ecma_value_t this_arg, /**< this argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_has (this_arg, value_arg, LIT_MAGIC_STRING_WEAKSET_UL); +} /* ecma_builtin_weakset_prototype_object_has */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.inc.h new file mode 100644 index 000000000..9ee89842e --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset-prototype.inc.h @@ -0,0 +1,45 @@ +/* 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. + */ + +/* + * WeakSet.prototype built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.4.3.2 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_WEAKSET, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) + +/* ECMA-262 v6, 23.4.3.5 */ +STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_WEAKSET_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_MAGIC_STRING_ADD, ecma_builtin_weakset_prototype_object_add, 1, 1) +ROUTINE (LIT_MAGIC_STRING_DELETE, ecma_builtin_weakset_prototype_object_delete, 1, 1) +ROUTINE (LIT_MAGIC_STRING_HAS, ecma_builtin_weakset_prototype_object_has, 1, 1) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.c b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.c new file mode 100644 index 000000000..823abde8a --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.c @@ -0,0 +1,74 @@ +/* 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. + */ + +#include "ecma-builtins.h" +#include "ecma-exceptions.h" +#include "ecma-container-object.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-weakset.inc.h" +#define BUILTIN_UNDERSCORED_ID weakset +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup weakset ECMA WeakSet object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in WeakSet object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_weakset_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor WeakSet requires 'new'.")); +} /* ecma_builtin_weakset_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in WeakSet object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_weakset_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_op_container_create (arguments_list_p, + arguments_list_len, + LIT_MAGIC_STRING_WEAKSET_UL, + ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE); +} /* ecma_builtin_weakset_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.inc.h new file mode 100644 index 000000000..a4f1be668 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakset.inc.h @@ -0,0 +1,47 @@ +/* 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. + */ + +/* + * WeakSet built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + +/* Number properties: + * (property name, number value, writable, enumerable, configurable) */ + +/* ECMA-262 v6, 23.4.2 */ +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 0, + ECMA_PROPERTY_FIXED) + +/* ECMA-262 v6, 23.4 */ +STRING_VALUE (LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_WEAKSET_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.4.2.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE, + ECMA_PROPERTY_FIXED) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h index 0ee7f21e8..ed010d1b9 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -472,6 +472,42 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_SET, #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + +/* The WeakMap prototype object (23.1.3) */ +BUILTIN (ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + weakmap_prototype) + +/* The WeakMap routine (ECMA-262 v6, 23.1.1.1) */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_WEAKMAP, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + weakmap) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + +/* The WeakSet prototype object (23.1.3) */ +BUILTIN (ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + weakset_prototype) + +/* The WeakSet routine (ECMA-262 v6, 23.1.1.1) */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_WEAKSET, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + weakset) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + #if ENABLED (JERRY_ES2015) /* The Symbol prototype object (ECMA-262 v6, 19.4.2.7) */ diff --git a/jerry-core/ecma/operations/ecma-container-object.c b/jerry-core/ecma/operations/ecma-container-object.c index c01b3d7d0..585a77d6d 100644 --- a/jerry-core/ecma/operations/ecma-container-object.c +++ b/jerry-core/ecma/operations/ecma-container-object.c @@ -26,17 +26,17 @@ #include "ecma-property-hashmap.h" #include "ecma-objects.h" -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) /** \addtogroup ecma ECMA * @{ * - * \addtogroup \addtogroup ecmamaphelpers ECMA builtin map/set helper functions + * \addtogroup \addtogroup ecmamaphelpers ECMA builtin Map/Set helper functions * @{ */ /** - * Handle calling [[Construct]] of built-in map/set like objects + * Handle calling [[Construct]] of built-in Map/Set like objects * * @return ecma value */ @@ -47,179 +47,216 @@ ecma_op_container_create (const ecma_value_t *arguments_list_p, /**< arguments l ecma_builtin_id_t proto_id) /**< prototype builtin id */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + JERRY_ASSERT (lit_id == LIT_MAGIC_STRING_MAP_UL + || lit_id == LIT_MAGIC_STRING_SET_UL + || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL + || lit_id == LIT_MAGIC_STRING_WEAKSET_UL); - ecma_object_t *internal_object_p = ecma_create_object (NULL, 0, ECMA_OBJECT_TYPE_GENERAL); + ecma_object_t *internal_object_p = ecma_create_object (NULL, + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_CLASS); + + ecma_extended_object_t *container_p = (ecma_extended_object_t *) internal_object_p; + container_p->u.class_prop.class_id = LIT_INTERNAL_MAGIC_STRING_CONTAINER; + container_p->u.class_prop.extra_info = ECMA_CONTAINER_FLAGS_EMPTY; + container_p->u.class_prop.u.length = 0; + + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL) + { + container_p->u.class_prop.extra_info |= ECMA_CONTAINER_FLAGS_WEAK; + } ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (proto_id), - sizeof (ecma_map_object_t), + sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS); - ecma_map_object_t *map_obj_p = (ecma_map_object_t *) object_p; - map_obj_p->header.u.class_prop.class_id = (uint16_t) lit_id; - map_obj_p->header.u.class_prop.u.value = ecma_make_object_value (internal_object_p); - map_obj_p->size = 0; + ecma_extended_object_t *map_obj_p = (ecma_extended_object_t *) object_p; + map_obj_p->u.class_prop.class_id = (uint16_t) lit_id; + ECMA_SET_INTERNAL_VALUE_POINTER (map_obj_p->u.class_prop.u.value, container_p); ecma_deref_object (internal_object_p); ecma_value_t set_value = ecma_make_object_value (object_p); + ecma_value_t result = set_value; #if ENABLED (JERRY_ES2015) if (arguments_list_len == 0) { - return set_value; + return result; } ecma_value_t iterable = arguments_list_p[0]; if (ecma_is_value_undefined (iterable) || ecma_is_value_null (iterable)) { - return set_value; + return result; } - ecma_value_t iter = ecma_op_get_iterator (iterable, ECMA_VALUE_EMPTY); - - if (ECMA_IS_VALUE_ERROR (iter)) + lit_magic_string_id_t adder_string_id; + if (lit_id == LIT_MAGIC_STRING_MAP_UL || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL) { - ecma_deref_object (object_p); - return iter; + adder_string_id = LIT_MAGIC_STRING_SET; } + else + { + adder_string_id = LIT_MAGIC_STRING_ADD; + } + + result = ecma_op_object_get_by_magic_id (object_p, adder_string_id); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_object; + } + + if (!ecma_op_is_callable (result)) + { + ecma_free_value (result); + result = ecma_raise_type_error (ECMA_ERR_MSG ("add/set function is not callable.")); + goto cleanup_object; + } + + ecma_object_t *adder_func_p = ecma_get_object_from_value (result); + + result = ecma_op_get_iterator (iterable, ECMA_VALUE_EMPTY); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_adder; + } + + const ecma_value_t iter = result; while (true) { - ecma_value_t next = ecma_op_iterator_step (iter); + result = ecma_op_iterator_step (iter); - if (ECMA_IS_VALUE_ERROR (next)) + if (ECMA_IS_VALUE_ERROR (result)) { - ecma_free_value (iter); - ecma_deref_object (object_p); - return next; + goto cleanup_iter; } - if (ecma_is_value_false (next)) + if (ecma_is_value_false (result)) { break; } - ecma_value_t next_value = ecma_op_iterator_value (next); - - if (ECMA_IS_VALUE_ERROR (next_value)) - { - ecma_free_value (next); - ecma_free_value (iter); - ecma_deref_object (object_p); - return next_value; - } - - ecma_value_t result; - if (lit_id == LIT_MAGIC_STRING_SET_UL) - { - result = ecma_op_container_set (set_value, next_value, next_value, lit_id); - } - else - { - if (!ecma_is_value_object (next_value)) - { - // TODO close the iterator when generator function will be supported - ecma_free_value (next_value); - ecma_free_value (next); - ecma_free_value (iter); - ecma_deref_object (object_p); - return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator value is not an object.")); - } - - ecma_object_t *next_object_p = ecma_get_object_from_value (next_value); - - ecma_value_t key = ecma_op_object_get_by_uint32_index (next_object_p, 0); - - if (ECMA_IS_VALUE_ERROR (key)) - { - // TODO close the iterator when generator function will be supported - ecma_free_value (next_value); - ecma_free_value (next); - ecma_free_value (iter); - ecma_deref_object (object_p); - return key; - } - - ecma_value_t value = ecma_op_object_get_by_uint32_index (next_object_p, 1); - - if (ECMA_IS_VALUE_ERROR (value)) - { - // TODO close the iterator when generator function will be supported - ecma_free_value (next_value); - ecma_free_value (key); - ecma_free_value (next); - ecma_free_value (iter); - ecma_deref_object (object_p); - return value; - } - - result = ecma_op_container_set (set_value, key, value, lit_id); - - ecma_free_value (key); - ecma_free_value (value); - } - - ecma_free_value (next_value); + const ecma_value_t next = result; + result = ecma_op_iterator_value (next); ecma_free_value (next); + if (ECMA_IS_VALUE_ERROR (result)) + { + goto cleanup_iter; + } + + if (lit_id == LIT_MAGIC_STRING_SET_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL) + { + const ecma_value_t value = result; + + ecma_value_t arguments[] = { value }; + result = ecma_op_function_call (adder_func_p, set_value, arguments, 1); + + ecma_free_value (value); + } + else + { + if (!ecma_is_value_object (result)) + { + // TODO close the iterator when generator function will be supported + ecma_free_value (result); + result = ecma_raise_type_error (ECMA_ERR_MSG ("Iterator value is not an object.")); + goto cleanup_iter; + } + + ecma_object_t *next_object_p = ecma_get_object_from_value (result); + + result = ecma_op_object_get_by_uint32_index (next_object_p, 0); + + if (ECMA_IS_VALUE_ERROR (result)) + { + // TODO close the iterator when generator function will be supported + ecma_deref_object (next_object_p); + goto cleanup_iter; + } + + const ecma_value_t key = result; + + result = ecma_op_object_get_by_uint32_index (next_object_p, 1); + + if (ECMA_IS_VALUE_ERROR (result)) + { + // TODO close the iterator when generator function will be supported + ecma_deref_object (next_object_p); + ecma_free_value (key); + goto cleanup_iter; + } + + const ecma_value_t value = result; + ecma_value_t arguments[] = { key, value }; + result = ecma_op_function_call (adder_func_p, set_value, arguments, 2); + + ecma_free_value (key); + ecma_free_value (value); + ecma_deref_object (next_object_p); + } + + if (ECMA_IS_VALUE_ERROR (result)) { // TODO close the iterator when generator function will be supported - ecma_free_value (iter); - ecma_deref_object (object_p); - return result; + goto cleanup_iter; } ecma_free_value (result); } ecma_free_value (iter); + ecma_deref_object (adder_func_p); + return ecma_make_object_value (object_p); +cleanup_iter: + ecma_free_value (iter); +cleanup_adder: + ecma_deref_object (adder_func_p); +cleanup_object: + ecma_deref_object (object_p); #endif /* ENABLED (JERRY_ES2015) */ - return set_value; + return result; } /* ecma_op_container_create */ /** - * Get map/set object pointer + * Get Map/Set object pointer * * Note: * If the function returns with NULL, the error object has * already set, and the caller must return with ECMA_VALUE_ERROR * - * @return pointer to the map/set if this_arg is a valid map/set object + * @return pointer to the Map/Set if this_arg is a valid Map/Set object * NULL otherwise */ -static ecma_map_object_t * +static ecma_extended_object_t * ecma_op_container_get_object (ecma_value_t this_arg, /**< this argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { if (ecma_is_value_object (this_arg)) { - ecma_map_object_t *map_object_p = (ecma_map_object_t *) ecma_get_object_from_value (this_arg); + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) ecma_get_object_from_value (this_arg); - if (ecma_get_object_type (&map_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS - && map_object_p->header.u.class_prop.class_id == lit_id) + if (ecma_get_object_type ((ecma_object_t *) map_object_p) == ECMA_OBJECT_TYPE_CLASS + && map_object_p->u.class_prop.class_id == lit_id) { return map_object_p; } } -#ifdef JERRY_ENABLE_ERROR_MESSAGES - char *msg_p = "Expected a Map object."; - -#if ENABLED (JERRY_ES2015_BUILTIN_SET) - if (lit_id == LIT_MAGIC_STRING_SET_UL) - { - msg_p = "Expected a Set object."; - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ - - ecma_raise_type_error (ECMA_ERR_MSG (msg_p)); -#else /* !JERRY_ENABLE_ERROR_MESSAGES */ +#if ENABLED (JERRY_ERROR_MESSAGES) + ecma_raise_standard_error_with_format (ECMA_ERROR_TYPE, + "Expected a % object.", + ecma_make_string_value (ecma_get_magic_string (lit_id))); +#else /* !ENABLED (JERRY_ERROR_MESSAGES) */ ecma_raise_type_error (NULL); -#endif /* JERRY_ENABLE_ERROR_MESSAGES */ +#endif /* ENABLED (JERRY_ERROR_MESSAGES) */ return NULL; } /* ecma_op_container_get_object */ @@ -242,37 +279,6 @@ ecma_op_container_to_key (ecma_value_t key_arg) /**< key argument */ return prop_name_p; } - if (ecma_is_value_object (key_arg)) - { - ecma_object_t *obj_p = ecma_get_object_from_value (key_arg); - ecma_string_t *key_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_MAP_KEY); - - if (ecma_op_object_is_fast_array (obj_p)) - { - ecma_fast_array_convert_to_normal (obj_p); - } - - ecma_property_t *property_p = ecma_find_named_property (obj_p, key_string_p); - ecma_string_t *object_key_string; - - if (property_p == NULL) - { - object_key_string = ecma_new_map_key_string (key_arg); - ecma_property_value_t *value_p = ecma_create_named_data_property (obj_p, - key_string_p, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, - NULL); - value_p->value = ecma_make_string_value (object_key_string); - } - else - { - object_key_string = ecma_get_string_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); - } - - ecma_ref_ecma_string (object_key_string); - return object_key_string; - } - if (ecma_is_value_integer_number (key_arg)) { ecma_integer_value_t integer = ecma_get_integer_from_value (key_arg); @@ -287,51 +293,62 @@ ecma_op_container_to_key (ecma_value_t key_arg) /**< key argument */ } /* ecma_op_container_to_key */ /** - * Returns with the size of the map/set object. + * Returns with the size of the Map/Set object. * - * @return size of the map/set object as ecma-value. + * @return size of the Map/Set object as ecma-value. */ ecma_value_t ecma_op_container_size (ecma_value_t this_arg, /**< this argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - return ecma_make_uint32_value (map_object_p->size); + ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, + map_object_p->u.class_prop.u.value); + return ecma_make_uint32_value (container_p->u.class_prop.u.length); } /* ecma_op_container_size */ /** - * The generic map prototype object's 'get' routine + * The generic Map/WeakMap prototype object's 'get' routine * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_op_container_get (ecma_value_t this_arg, /**< this argument */ - ecma_value_t key_arg) /**< key argument */ + ecma_value_t key_arg, /**< key argument */ + lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, LIT_MAGIC_STRING_MAP_UL); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - if (map_object_p->size == 0) +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL && !ecma_is_value_object (key_arg)) + { + return ECMA_VALUE_UNDEFINED; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + + ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, + map_object_p->u.class_prop.u.value); + + if (container_p->u.class_prop.u.length == 0) { return ECMA_VALUE_UNDEFINED; } - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); + ecma_property_t *property_p = ecma_find_named_property ((ecma_object_t *) container_p, prop_name_p); ecma_deref_ecma_string (prop_name_p); @@ -344,7 +361,7 @@ ecma_op_container_get (ecma_value_t this_arg, /**< this argument */ } /* ecma_op_container_get */ /** - * The generic map/set prototype object's 'has' routine + * The generic Map/Set prototype object's 'has' routine * * @return ecma value * Returned value must be freed with ecma_free_value. @@ -354,23 +371,32 @@ ecma_op_container_has (ecma_value_t this_arg, /**< this argument */ ecma_value_t key_arg, /**< key argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - if (map_object_p->size == 0) +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + if ((lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL) + && !ecma_is_value_object (key_arg)) + { + return ECMA_VALUE_FALSE; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + + ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, + map_object_p->u.class_prop.u.value); + + if (container_p->u.class_prop.u.length == 0) { return ECMA_VALUE_FALSE; } - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); + ecma_property_t *property_p = ecma_find_named_property ((ecma_object_t *) container_p, prop_name_p); ecma_deref_ecma_string (prop_name_p); @@ -379,7 +405,7 @@ ecma_op_container_has (ecma_value_t this_arg, /**< this argument */ } /* ecma_op_container_has */ /** - * The generic map prototype object's 'set' and set prototype object's 'add' routine + * The generic Map prototype object's 'set' and Set prototype object's 'add' routine * * @return ecma value * Returned value must be freed with ecma_free_value. @@ -390,44 +416,114 @@ ecma_op_container_set (ecma_value_t this_arg, /**< this argument */ ecma_value_t value_arg, /**< value argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); + ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, + map_object_p->u.class_prop.u.value); ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); + ecma_property_t *property_p = ecma_find_named_property ((ecma_object_t *) container_p, prop_name_p); if (property_p == NULL) { - ecma_property_value_t *value_p = ecma_create_named_data_property (internal_obj_p, + ecma_property_value_t *value_p = ecma_create_named_data_property ((ecma_object_t *) container_p, prop_name_p, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL); value_p->value = ecma_copy_value_if_not_object (value_arg); - map_object_p->size++; + container_p->u.class_prop.u.length++; } else { if (ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) { - map_object_p->size++; + container_p->u.class_prop.u.length++; } - ecma_named_data_property_assign_value (internal_obj_p, ECMA_PROPERTY_VALUE_PTR (property_p), value_arg); + + ecma_named_data_property_assign_value ((ecma_object_t *) container_p, + ECMA_PROPERTY_VALUE_PTR (property_p), + value_arg); } ecma_deref_ecma_string (prop_name_p); - ecma_ref_object ((ecma_object_t *) &map_object_p->header); + ecma_ref_object ((ecma_object_t *) map_object_p); return this_arg; } /* ecma_op_container_set */ /** - * The generic map/set prototype object's 'forEach' routine + * The generic WeakMap prototype object's 'set' and WeakSet prototype object's 'add' routine + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_op_container_set_weak (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg, /**< key argument */ + ecma_value_t value_arg, /**< value argument */ + lit_magic_string_id_t lit_id) /**< internal class id */ +{ + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + + if (map_object_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + if (!ecma_is_value_object (key_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Key must be an object")); + } + + /* This will increment the refcount on map_object_p */ + ecma_op_container_set (this_arg, key_arg, value_arg, lit_id); + + ecma_object_t *obj_p = ecma_get_object_from_value (key_arg); + ecma_string_t *weak_refs_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS); + + ecma_property_t *property_p = ecma_find_named_property (obj_p, weak_refs_string_p); + ecma_collection_t *refs_p; + + if (property_p == NULL) + { + ecma_property_value_t *value_p = ecma_create_named_data_property (obj_p, + weak_refs_string_p, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + &property_p); + ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p); + refs_p = ecma_new_collection (); + ECMA_SET_INTERNAL_VALUE_POINTER (value_p->value, refs_p); + } + else + { + refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, (ECMA_PROPERTY_VALUE_PTR (property_p)->value)); + } + + ecma_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + map_object_p->u.class_prop.u.value); + + const ecma_value_t container_value = ecma_make_object_value (container_p); + + for (uint32_t i = 0; i < refs_p->item_count; i++) + { + if (ecma_is_value_empty (refs_p->buffer_p[i])) + { + refs_p->buffer_p[i] = container_value; + return this_arg; + } + } + + ecma_collection_push_back (refs_p, container_value); + return this_arg; +} /* ecma_op_container_set_weak */ + +/** + * The generic Map/Set prototype object's 'forEach' routine * * @return ecma value * Returned value must be freed with ecma_free_value. @@ -439,7 +535,7 @@ ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */ * invoke predicate */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { @@ -454,20 +550,21 @@ ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */ JERRY_ASSERT (ecma_is_value_object (predicate)); ecma_object_t *func_object_p = ecma_get_object_from_value (predicate); - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); + ecma_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + map_object_p->u.class_prop.u.value); - ecma_collection_t *props_p = ecma_op_object_get_property_names (internal_obj_p, ECMA_LIST_NO_OPTS); + ecma_collection_t *props_p = ecma_op_object_get_property_names (container_p, ECMA_LIST_NO_OPTS); ecma_value_t *buffer_p = props_p->buffer_p; ecma_value_t ret_value = ECMA_VALUE_UNDEFINED; - ecma_ref_object (internal_obj_p); + ecma_ref_object (container_p); for (uint32_t i = 0; i < props_p->item_count; i++) { ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (buffer_p[i]); - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); + ecma_property_t *property_p = ecma_find_named_property (container_p, prop_name_p); JERRY_ASSERT (property_p != NULL); if (ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) @@ -514,7 +611,7 @@ ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */ ecma_free_value (call_value); } - ecma_deref_object (internal_obj_p); + ecma_deref_object (container_p); ecma_collection_free (props_p); return ret_value; @@ -530,16 +627,23 @@ ecma_value_t ecma_op_container_clear (ecma_value_t this_arg, /**< this argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - ecma_object_t *internal_object_p = ecma_create_object (NULL, 0, ECMA_OBJECT_TYPE_GENERAL); - map_object_p->header.u.class_prop.u.value = ecma_make_object_value (internal_object_p); - map_object_p->size = 0; + ecma_object_t *internal_object_p = ecma_create_object (NULL, + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_CLASS); + + ecma_extended_object_t *container_p = (ecma_extended_object_t *) internal_object_p; + container_p->u.class_prop.class_id = LIT_INTERNAL_MAGIC_STRING_CONTAINER; + container_p->u.class_prop.extra_info = ECMA_CONTAINER_FLAGS_EMPTY; + container_p->u.class_prop.u.length = 0; + + ECMA_SET_INTERNAL_VALUE_POINTER (map_object_p->u.class_prop.u.value, internal_object_p); ecma_deref_object (internal_object_p); @@ -547,7 +651,7 @@ ecma_op_container_clear (ecma_value_t this_arg, /**< this argument */ } /* ecma_op_container_clear */ /** - * The generic map/set prototype object's 'delete' routine + * The generic Map/Set prototype object's 'delete' routine * * @return ecma value * Returned value must be freed with ecma_free_value. @@ -557,18 +661,19 @@ ecma_op_container_delete (ecma_value_t this_arg, /**< this argument */ ecma_value_t key_arg, /**< key argument */ lit_magic_string_id_t lit_id) /**< internal class id */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); + ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, + map_object_p->u.class_prop.u.value); ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); + ecma_property_t *property_p = ecma_find_named_property ((ecma_object_t *) container_p, prop_name_p); ecma_deref_ecma_string (prop_name_p); @@ -577,12 +682,107 @@ ecma_op_container_delete (ecma_value_t this_arg, /**< this argument */ return ECMA_VALUE_FALSE; } - ecma_named_data_property_assign_value (internal_obj_p, ECMA_PROPERTY_VALUE_PTR (property_p), ECMA_VALUE_EMPTY); - map_object_p->size--; + + ecma_named_data_property_assign_value ((ecma_object_t *) container_p, + ECMA_PROPERTY_VALUE_PTR (property_p), + ECMA_VALUE_EMPTY); + container_p->u.class_prop.u.length--; return ECMA_VALUE_TRUE; } /* ecma_op_container_delete */ +/** + * The generic WeakMap/WeakSet prototype object's 'delete' routine + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_op_container_delete_weak (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg, /**< key argument */ + lit_magic_string_id_t lit_id) /**< internal class id */ +{ + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + + if (map_object_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + if (!ecma_is_value_object (key_arg)) + { + return ECMA_VALUE_FALSE; + } + + ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, + map_object_p->u.class_prop.u.value); + + ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); + + ecma_property_t *property_p = ecma_find_named_property ((ecma_object_t *) container_p, prop_name_p); + + ecma_deref_ecma_string (prop_name_p); + + if (property_p == NULL) + { + return ECMA_VALUE_FALSE; + } + + ecma_delete_property ((ecma_object_t *) container_p, ECMA_PROPERTY_VALUE_PTR (property_p)); + + ecma_object_t *internal_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + map_object_p->u.class_prop.u.value); + ecma_object_t *key_object_p = ecma_get_object_from_value (key_arg); + ecma_op_container_unref_weak (key_object_p, ecma_make_object_value (internal_obj_p)); + + return ECMA_VALUE_TRUE; +} /* ecma_op_container_delete_weak */ + +/** + * Helper function to remove a weak reference to an object. + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +void +ecma_op_container_unref_weak (ecma_object_t *object_p, /**< this argument */ + ecma_value_t ref_holder) /**< key argument */ +{ + ecma_string_t *weak_refs_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS); + + ecma_property_t *property_p = ecma_find_named_property (object_p, weak_refs_string_p); + JERRY_ASSERT (property_p != NULL); + + ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + ECMA_PROPERTY_VALUE_PTR (property_p)->value); + for (uint32_t i = 0; i < refs_p->item_count; i++) + { + if (refs_p->buffer_p[i] == ref_holder) + { + refs_p->buffer_p[i] = ECMA_VALUE_EMPTY; + break; + } + } +} /* ecma_op_container_unref_weak */ + +/** + * Helper function to remove a key/value pair from a weak container object + */ +void +ecma_op_container_remove_weak_entry (ecma_object_t *container_p, /**< internal container object */ + ecma_value_t key_arg) /**< key */ +{ + ecma_string_t *prop_name_p = ecma_new_map_key_string (key_arg); + + ecma_property_t *property_p = ecma_find_named_property (container_p, prop_name_p); + JERRY_ASSERT (property_p != NULL); + + ecma_deref_ecma_string (prop_name_p); + + ecma_delete_property (container_p, ECMA_PROPERTY_VALUE_PTR (property_p)); + ((ecma_extended_object_t *) container_p)->u.class_prop.u.length--; +} /* ecma_op_container_remove_weak_entry */ + #if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) /** @@ -595,7 +795,7 @@ ecma_op_container_delete (ecma_value_t this_arg, /**< this argument */ * Note: * Returned value must be freed with ecma_free_value. * - * @return set/map iterator object, if success + * @return Map/Set iterator object, if success * error - otherwise */ ecma_value_t @@ -606,7 +806,7 @@ ecma_op_container_create_iterator (ecma_value_t this_arg, /**< this argument */ ecma_builtin_id_t proto_id, /**< prototype builtin id */ ecma_pseudo_array_type_t iterator_type) /**< type of the iterator */ { - ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); + ecma_extended_object_t *map_object_p = ecma_op_container_get_object (this_arg, lit_id); if (map_object_p == NULL) { @@ -657,9 +857,10 @@ ecma_op_container_iterator_next (ecma_value_t this_val, /**< this argument */ return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); } - ecma_map_object_t *map_object_p = (ecma_map_object_t *) (ecma_get_object_from_value (iterated_value)); + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) (ecma_get_object_from_value (iterated_value)); - ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); + ecma_object_t *internal_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + map_object_p->u.class_prop.u.value); ecma_collection_t *props_p = ecma_op_object_get_property_names (internal_obj_p, ECMA_LIST_NO_OPTS); uint32_t length = props_p->item_count; @@ -783,4 +984,4 @@ ecma_op_container_iterator_next (ecma_value_t this_val, /**< this argument */ * @} */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ diff --git a/jerry-core/ecma/operations/ecma-container-object.h b/jerry-core/ecma/operations/ecma-container-object.h index 6959d2b9d..673ca3fce 100644 --- a/jerry-core/ecma/operations/ecma-container-object.h +++ b/jerry-core/ecma/operations/ecma-container-object.h @@ -19,7 +19,7 @@ #include "ecma-globals.h" #include "ecma-builtins.h" -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) /** \addtogroup ecma ECMA * @{ @@ -31,15 +31,20 @@ ecma_value_t ecma_op_container_create (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len, lit_magic_string_id_t lit_id, ecma_builtin_id_t proto_id); ecma_value_t ecma_op_container_size (ecma_value_t this_arg, lit_magic_string_id_t lit_id); -ecma_value_t ecma_op_container_get (ecma_value_t this_arg, ecma_value_t key_arg); +ecma_value_t ecma_op_container_get (ecma_value_t this_arg, ecma_value_t key_arg, lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_foreach (ecma_value_t this_arg, ecma_value_t predicate, ecma_value_t predicate_this_arg, lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_has (ecma_value_t this_arg, ecma_value_t key_arg, lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_set (ecma_value_t this_arg, ecma_value_t key_arg, ecma_value_t value_arg, lit_magic_string_id_t lit_id); +ecma_value_t ecma_op_container_set_weak (ecma_value_t this_arg, ecma_value_t key_arg, ecma_value_t value_arg, + lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_clear (ecma_value_t this_arg, lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_delete (ecma_value_t this_arg, ecma_value_t key_arg, lit_magic_string_id_t lit_id); +ecma_value_t ecma_op_container_delete_weak (ecma_value_t this_arg, ecma_value_t key_arg, lit_magic_string_id_t lit_id); +void ecma_op_container_unref_weak (ecma_object_t *object_p, ecma_value_t ref_holder); +void ecma_op_container_remove_weak_entry (ecma_object_t *container_p, ecma_value_t key_arg); ecma_value_t ecma_op_container_create_iterator (ecma_value_t this_arg, uint8_t type, lit_magic_string_id_t lit_id, ecma_builtin_id_t proto_id, ecma_pseudo_array_type_t iterator_type); ecma_value_t ecma_op_container_iterator_next (ecma_value_t this_val, ecma_pseudo_array_type_t iterator_type); @@ -49,6 +54,6 @@ ecma_value_t ecma_op_container_iterator_next (ecma_value_t this_val, ecma_pseudo * @} */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ #endif /* !ECMA_CONTAINER_OBJECT_H */ diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h index 509b99953..92e378937 100644 --- a/jerry-core/lit/lit-magic-strings.h +++ b/jerry-core/lit/lit-magic-strings.h @@ -70,6 +70,8 @@ typedef enum LIT_FIRST_INTERNAL_MAGIC_STRING = LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< first index of internal * magic strings */ LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING, /**< the this binding of the class constructor */ + LIT_INTERNAL_MAGIC_STRING_WEAK_REFS, /**< Weak references to the current object */ + LIT_INTERNAL_MAGIC_STRING_CONTAINER, /**< Literal ID for internal container objects */ LIT_MAGIC_STRING__COUNT /**< number of magic strings */ } lit_magic_string_id_t; diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index aea9df57e..eeefd538d 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -44,12 +44,12 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_OF, "of") #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LN2_U, "LN2") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_MAP) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MAP_UL, "Map") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NAN, "NaN") -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) \ +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ || ENABLED (JERRY_ES2015_BUILTIN_SET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UL, "Set") #endif @@ -59,7 +59,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UTC_U, "UTC") #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ABS, "abs") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_SET) +#if ENABLED (JERRY_ES2015) && ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_SET) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ADD, "add") #endif #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) @@ -74,7 +76,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FOR, "for") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET, "get") #if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_SET) +|| ENABLED (JERRY_ES2015_BUILTIN_SET) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_HAS, "has") #endif #if ENABLED (JERRY_BUILTIN_MATH) @@ -277,7 +281,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CONCAT, "concat") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CREATE, "create") #if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_SET) +|| ENABLED (JERRY_ES2015_BUILTIN_SET) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DELETE, "delete") #endif #if ENABLED (JERRY_BUILTIN_ANNEXB) @@ -362,6 +368,14 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SQRT1_2_U, "SQRT1_2") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL_LEFT_PAREN_UL, "Symbol(") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL_DOT_UL, "Symbol.") #endif +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKMAP_UL, "WeakMap") +#endif +#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKSET_UL, "WeakSet") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BOOLEAN, "boolean") #if ENABLED (JERRY_BUILTIN_ANNEXB) && ENABLED (JERRY_BUILTIN_REGEXP) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMPILE, "compile") @@ -791,16 +805,16 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_IS) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_OF) #elif ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_LN2_U) -#elif ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#elif ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_MAP) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_MAP_UL) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_NAN) #endif #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (3, LIT_MAGIC_STRING_LN2_U) -#elif ENABLED (JERRY_ES2015_BUILTIN_MAP) \ -|| ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) +#elif ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) \ +|| ENABLED (JERRY_ES2015_BUILTIN_MAP) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (3, LIT_MAGIC_STRING_MAP_UL) #else LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (3, LIT_MAGIC_STRING_NAN) diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index a1fd4b246..ee3f678eb 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -181,6 +181,8 @@ LIT_MAGIC_STRING_SPECIES = "species" LIT_MAGIC_STRING_TO_FIXED_UL = "toFixed" LIT_MAGIC_STRING_UNSHIFT = "unshift" LIT_MAGIC_STRING_VALUE_OF_UL = "valueOf" +LIT_MAGIC_STRING_WEAKMAP_UL = "WeakMap" +LIT_MAGIC_STRING_WEAKSET_UL = "WeakSet" LIT_MAGIC_STRING_EPSILON_U = "EPSILON" LIT_MAGIC_STRING_DATAVIEW_UL = "DataView" LIT_MAGIC_STRING_FUNCTION_UL = "Function" diff --git a/tests/jerry/es2015/weakmap.js b/tests/jerry/es2015/weakmap.js new file mode 100644 index 000000000..5eef6419b --- /dev/null +++ b/tests/jerry/es2015/weakmap.js @@ -0,0 +1,138 @@ +/* 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. + */ + +var m1 = new WeakMap(); +var k1 = {}; +assert (m1.set (k1, 3.14) instanceof WeakMap); +assert (m1.has (k1) === true); +assert (m1.get (k1) === 3.14); + +k1 = {}; +gc (); /* This will remove the entry, but there is no way to validate it from js. */ + +assert (m1.has (k1) === false); +assert (m1.delete(k1) === false); +assert (m1.set (k1, "asd" + "fgh") instanceof WeakMap); +assert (m1.has (k1) === true); +assert (m1.get (k1) === "asdfgh"); + +assert (m1.delete ("str") === false); +assert (m1.has (42) === false); +assert (m1.get (42) === undefined); +try { + m1.set (42, 42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +gc (); +assert (m1.delete(k1) === true); +gc (); +assert (m1.has (k1) === false); +k1 = {}; +gc (); + +Object.freeze(k1); +assert (m1.set (k1, "frozen") instanceof WeakMap); +assert (m1.has (k1) === true); +assert (m1.get (k1) === "frozen"); +k1 = {}; +gc (); + +var m2 = new WeakMap(); + +m1.set (k1, "str" + "str"); +m2.set (k1, 42.42); + +k1 = {}; +gc (); +var k2 = {}; + +m1.set (k1, "str" + "str"); +m1.set (k2, "str2" + "str2"); +m2.set (k1, 42.42); +m2.set (k2, Infinity); + +m2.delete (k1); +gc (); +k1 = {}; +k2 = {}; +gc (); + +var k3 = {}; +m1 = new WeakMap(); +m1.set(k1, "str" + "str"); +m1.set(k2, "str2" + "str2"); +m1.set(k3, "str3" + "str3"); +k1 = undefined; +k2 = undefined; +k3 = undefined; +m1 = undefined; +gc(); + +try { + WeakMap(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + WeakMap.prototype.get.call({}); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +assert (new WeakMap(null) instanceof WeakMap); + +k1 = {}; +k2 = {}; +m1 = new WeakMap([[k1, 1.2], [k2, 1.3]]); +assert (m1.has (k1)); +assert (m1.has (k2)); +assert (m1.get (k1) === 1.2); +assert (m1.get (k2) === 1.3); +gc(); +m1 = undefined; +gc(); + +try { + new WeakMap([[1,2],[3,4]]); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +WeakMap.prototype.set = function () { throw "abrupt set" }; + +try { + new WeakMap([[{}, 1]]); + assert (false); +} catch (e) { + assert (e === "abrupt set"); +} + +Object.defineProperty(WeakMap.prototype, 'set', { + get: () => { throw "abrupt set getter" } +}); + +try { + new WeakMap([]); + assert (false); +} catch (e) { + assert (e === "abrupt set getter"); +} diff --git a/tests/jerry/es2015/weakset.js b/tests/jerry/es2015/weakset.js new file mode 100644 index 000000000..a5adbae8a --- /dev/null +++ b/tests/jerry/es2015/weakset.js @@ -0,0 +1,123 @@ +/* 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. + */ + +var m1 = new WeakSet(); + +var k1 = {}; +assert (m1.add (k1) instanceof WeakSet); +assert (m1.has (k1) === true); + +k1 = {}; +gc (); /* This will remove the entry, but there is no way to validate it from js. */ + +assert (m1.has (k1) === false); +assert (m1.delete(k1) === false); +assert (m1.add (k1) instanceof WeakSet); +assert (m1.has (k1) === true); + +assert (m1.delete ("str") === false); +assert (m1.has (42) === false); + +try { + m1.add (42); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +gc (); +assert (m1.delete(k1) === true); +gc (); +assert (m1.has (k1) === false); +k1 = {}; +gc (); + +Object.freeze(k1); +assert (m1.add (k1) instanceof WeakSet); +assert (m1.has (k1) === true); +k1 = {}; +gc (); + +var m2 = new WeakSet(); + +k1 = {}; +gc (); +var k2 = {}; + +m1.add (k1); +m1.add (k2); +m2.add (k1); +m2.add (k2); + +m2.delete (k1); +gc (); +k1 = {}; +k2 = {}; +gc (); + +new WeakSet().add(new WeakSet().add(new WeakSet().add(new WeakSet().add(new WeakSet().add(new WeakSet().add(new WeakSet())))))); +gc(); + +try { + WeakSet(); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +try { + WeakSet.prototype.get.call({}); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +assert (new WeakSet(null) instanceof WeakSet); + +k1 = {}; +k2 = {}; +m1 = new WeakSet([k1, k2]); +assert (m1.has (k1)); +assert (m1.has (k2)); +gc(); +m1 = undefined; +gc(); + +try { + new WeakSet([1,2,3,4]); + assert (false); +} catch (e) { + assert (e instanceof TypeError); +} + +WeakSet.prototype.add = function () { throw "abrupt add" }; + +try { + new WeakSet([{}]); + assert (false); +} catch (e) { + assert (e === "abrupt add"); +} + +Object.defineProperty(WeakSet.prototype, 'add', { + get: () => { throw "abrupt add getter" } +}); + +try { + new WeakSet([]); + assert (false); +} catch (e) { + assert (e === "abrupt add getter"); +}