diff --git a/jerry-core/config.h b/jerry-core/config.h index 53249bbf63..013992468a 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -39,6 +39,7 @@ # define CONFIG_DISABLE_ES2015_ARROW_FUNCTION # define CONFIG_DISABLE_ES2015_BUILTIN # define CONFIG_DISABLE_ES2015_CLASS +# define CONFIG_DISABLE_ES2015_MAP_BUILTIN # define CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER # define CONFIG_DISABLE_ES2015_PROMISE_BUILTIN # define CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index a4b2d062bb..6039945f37 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -32,10 +32,13 @@ #ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN #include "ecma-typedarray-object.h" -#endif +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ #ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN #include "ecma-promise-object.h" -#endif +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN +#include "ecma-map-object.h" +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ /* TODO: Extract GC to a separate component */ @@ -206,6 +209,87 @@ ecma_gc_mark_property (ecma_property_pair_t *property_pair_p, /**< property pair } } /* ecma_gc_mark_property */ +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + +/** + * Mark objects referenced by Promise built-in. + */ +static void +ecma_gc_mark_promise_object (ecma_extended_object_t *ext_object_p) /**< extended object */ +{ + /* Mark promise result. */ + ecma_value_t result = ext_object_p->u.class_prop.u.value; + + if (ecma_is_value_object (result)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (result)); + } + + /* Mark all reactions. */ + ecma_value_t *ecma_value_p; + ecma_value_p = ecma_collection_iterator_init (((ecma_promise_object_t *) ext_object_p)->fulfill_reactions); + + while (ecma_value_p != NULL) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p)); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); + } + + ecma_value_p = ecma_collection_iterator_init (((ecma_promise_object_t *) ext_object_p)->reject_reactions); + + while (ecma_value_p != NULL) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p)); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); + } +} /* ecma_gc_mark_promise_object */ + +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ + +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + +/** + * Mark objects referenced by Map built-in. + */ +static void +ecma_gc_mark_map_object (ecma_extended_object_t *ext_object_p) /**< extended object */ +{ + ecma_map_object_t *map_object_p = (ecma_map_object_t *) ext_object_p; + + jmem_cpointer_t first_chunk_cp = map_object_p->first_chunk_cp; + + if (JERRY_UNLIKELY (first_chunk_cp == ECMA_NULL_POINTER)) + { + return; + } + + ecma_value_t *item_p = ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t, first_chunk_cp)->items; + + while (true) + { + ecma_value_t item = *item_p++; + + if (!ecma_is_value_pointer (item)) + { + if (ecma_is_value_object (item)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (item)); + } + } + else + { + item_p = (ecma_value_t *) ecma_get_pointer_from_value (item); + + if (item_p == NULL) + { + return; + } + } + } +} /* ecma_gc_mark_map_object */ + +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ + /** * Mark objects as visited starting from specified object as root */ @@ -243,43 +327,34 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ switch (ecma_get_object_type (object_p)) { -#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN case ECMA_OBJECT_TYPE_CLASS: { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - if (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_PROMISE_UL) + switch (ext_object_p->u.class_prop.class_id) { - /* Mark promise result. */ - ecma_value_t result = ext_object_p->u.class_prop.u.value; - - if (ecma_is_value_object (result)) +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + case LIT_MAGIC_STRING_PROMISE_UL: { - ecma_gc_set_object_visited (ecma_get_object_from_value (result)); + ecma_gc_mark_promise_object (ext_object_p); + break; } - - /* Mark all reactions. */ - ecma_value_t *ecma_value_p; - ecma_value_p = ecma_collection_iterator_init (((ecma_promise_object_t *) ext_object_p)->fulfill_reactions); - - while (ecma_value_p != NULL) +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + case LIT_MAGIC_STRING_MAP_UL: { - ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p)); - ecma_value_p = ecma_collection_iterator_next (ecma_value_p); + ecma_gc_mark_map_object (ext_object_p); + break; } - - ecma_value_p = ecma_collection_iterator_init (((ecma_promise_object_t *) ext_object_p)->reject_reactions); - - while (ecma_value_p != NULL) +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ + default: { - ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p)); - ecma_value_p = ecma_collection_iterator_next (ecma_value_p); + break; } } break; } -#endif /*! CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; @@ -582,6 +657,14 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ return; } #endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + case LIT_MAGIC_STRING_MAP_UL: + { + ecma_op_map_clear_map ((ecma_map_object_t *) object_p); + ecma_dealloc_extended_object (object_p, sizeof (ecma_map_object_t)); + return; + } +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ default: { /* The undefined id represents an uninitialized class. */ diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 9f04f7bd9a..ad8a710d01 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -74,13 +74,12 @@ typedef enum ECMA_TYPE_FLOAT = 2, /**< pointer to a 64 or 32 bit floating point number */ ECMA_TYPE_OBJECT = 3, /**< pointer to description of an object */ ECMA_TYPE_DIRECT_STRING = 5, /**< directly encoded string values */ - ECMA_TYPE_ERROR = 7, /**< pointer to description of an error reference */ - ECMA_TYPE_COLLECTION_CHUNK = ECMA_TYPE_ERROR, /**< pointer to description of a collection chunk */ + ECMA_TYPE_ERROR = 7, /**< pointer to description of an error reference (only supported by C API) */ + ECMA_TYPE_POINTER = ECMA_TYPE_ERROR, /**< a generic aligned pointer */ ECMA_TYPE_SNAPSHOT_OFFSET = ECMA_TYPE_ERROR, /**< offset to a snapshot number/string */ ECMA_TYPE___MAX = ECMA_TYPE_ERROR /** highest value for ecma types */ } ecma_type_t; - /** * Option flags for script parsing. */ @@ -166,11 +165,11 @@ enum ECMA_VALUE_UNDEFINED = ECMA_MAKE_VALUE (4), /**< undefined value */ ECMA_VALUE_NULL = ECMA_MAKE_VALUE (5), /**< null value */ ECMA_VALUE_ARRAY_HOLE = ECMA_MAKE_VALUE (6), /**< array hole, used for - * initialization of an array literal */ + * initialization of an array literal */ ECMA_VALUE_NOT_FOUND = ECMA_MAKE_VALUE (7), /**< a special value returned by - * ecma_op_object_find */ + * ecma_op_object_find */ ECMA_VALUE_REGISTER_REF = ECMA_MAKE_VALUE (8), /**< register reference, - * a special "base" value for vm */ + * a special "base" value for vm */ }; #if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 @@ -826,8 +825,8 @@ typedef struct */ typedef struct { - ecma_extended_object_t header; - const ecma_compiled_code_t *bytecode_p; + ecma_extended_object_t header; /**< header part */ + const ecma_compiled_code_t *bytecode_p; /**< real byte code pointer */ } ecma_static_function_t; #endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ @@ -860,6 +859,34 @@ typedef struct #endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + +/** + * Map item count of chunks + */ +#define ECMA_MAP_OBJECT_ITEM_COUNT 3 + +/** + * Description of Map objects. + */ +typedef struct +{ + ecma_extended_object_t header; /**< header part */ + jmem_cpointer_t first_chunk_cp; /**< first chunk of item list */ + jmem_cpointer_t last_chunk_cp; /**< last chunk of item list */ +} ecma_map_object_t; + +/** + * Description of Map memory chunk. + */ +typedef struct +{ + ecma_value_t items[ECMA_MAP_OBJECT_ITEM_COUNT + 1]; /**< the last item is always a pointer to the next chunk, + * the rest can be ECMA_VALUE_ARRAY_HOLE or any valid value. */ +} ecma_map_object_chunk_t; + +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ + /** * Description of ECMA property descriptor * diff --git a/jerry-core/ecma/base/ecma-helpers-value.c b/jerry-core/ecma/base/ecma-helpers-value.c index 73f8f47fce..1235cac25e 100644 --- a/jerry-core/ecma/base/ecma-helpers-value.c +++ b/jerry-core/ecma/base/ecma-helpers-value.c @@ -312,9 +312,9 @@ ecma_is_value_string (ecma_value_t value) /**< ecma value */ } /* ecma_is_value_string */ /** - * Check if the value is direct_ecma-string. + * Check if the value is direct ecma-string. * - * @return true - if the value contains ecma-string value, + * @return true - if the value contains direct ecma-string value, * false - otherwise */ inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE @@ -323,6 +323,18 @@ ecma_is_value_direct_string (ecma_value_t value) /**< ecma value */ return (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT_STRING); } /* ecma_is_value_direct_string */ +/** + * Check if the value is non-direct ecma-string. + * + * @return true - if the value contains non-direct ecma-string value, + * false - otherwise + */ +inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE +ecma_is_value_non_direct_string (ecma_value_t value) /**< ecma value */ +{ + return (ecma_get_value_type_field (value) == ECMA_TYPE_STRING); +} /* ecma_is_value_non_direct_string */ + /** * Check if the value is object. * @@ -348,16 +360,16 @@ ecma_is_value_error_reference (ecma_value_t value) /**< ecma value */ } /* ecma_is_value_error_reference */ /** - * Check if the value is collection chunk. + * Check if the value is an aligned pointer. * - * @return true - if the value contains a collection chunk, + * @return true - if the value contains an aligned pointer, * false - otherwise */ inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE -ecma_is_value_collection_chunk (ecma_value_t value) /**< ecma value */ +ecma_is_value_pointer (ecma_value_t value) /**< ecma value */ { - return (ecma_get_value_type_field (value) == ECMA_TYPE_COLLECTION_CHUNK); -} /* ecma_is_value_collection_chunk */ + return (ecma_get_value_type_field (value) == ECMA_TYPE_POINTER); +} /* ecma_is_value_pointer */ /** * Debug assertion that specified value's type is one of ECMA-defined @@ -566,27 +578,27 @@ ecma_make_error_reference_value (const ecma_error_reference_t *error_ref_p) /**< } /* ecma_make_error_reference_value */ /** - * Collection chunk constructor + * Create an ecma value from an aligned pointer * - * @return ecma-value representation of the collection chunk + * @return ecma-value representation of the aligned pointer */ inline ecma_value_t JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE -ecma_make_collection_chunk_value (const ecma_collection_chunk_t *collection_chunk_p) /**< collection chunk */ +ecma_make_pointer_value (const void *any_p) /**< any aligned pointer */ { #ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY - uintptr_t uint_ptr = (uintptr_t) collection_chunk_p; + uintptr_t uint_ptr = (uintptr_t) any_p; JERRY_ASSERT ((uint_ptr & ECMA_VALUE_TYPE_MASK) == 0); - return ((ecma_value_t) uint_ptr) | ECMA_TYPE_COLLECTION_CHUNK; + return ((ecma_value_t) uint_ptr) | ECMA_TYPE_POINTER; #else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ jmem_cpointer_t ptr_cp; - ECMA_SET_POINTER (ptr_cp, collection_chunk_p); - return (((ecma_value_t) ptr_cp) << ECMA_VALUE_SHIFT) | ECMA_TYPE_COLLECTION_CHUNK; + ECMA_SET_POINTER (ptr_cp, any_p); + return (((ecma_value_t) ptr_cp) << ECMA_VALUE_SHIFT) | ECMA_TYPE_POINTER; #endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ -} /* ecma_make_collection_chunk_value */ +} /* ecma_make_pointer_value */ /** * Get integer value from an integer ecma value @@ -675,21 +687,21 @@ ecma_get_error_reference_from_value (ecma_value_t value) /**< ecma value */ } /* ecma_get_error_reference_from_value */ /** - * Get pointer to collection chunk from ecma value + * Get an aligned pointer from an ecma value * - * @return the pointer + * @return pointer value */ -inline ecma_collection_chunk_t *JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE -ecma_get_collection_chunk_from_value (ecma_value_t value) /**< ecma value */ +inline void * JERRY_ATTR_PURE JERRY_ATTR_ALWAYS_INLINE +ecma_get_pointer_from_value (ecma_value_t value) /**< ecma value */ { - JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_COLLECTION_CHUNK); + JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_POINTER); #ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY - return (ecma_collection_chunk_t *) (uintptr_t) ((value) & ~ECMA_VALUE_TYPE_MASK); + return (void *) (uintptr_t) ((value) & ~ECMA_VALUE_TYPE_MASK); #else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ - return ECMA_GET_POINTER (ecma_collection_chunk_t, value >> ECMA_VALUE_SHIFT); + return ECMA_GET_POINTER (void, value >> ECMA_VALUE_SHIFT); #endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ -} /* ecma_get_collection_chunk_from_value */ +} /* ecma_get_pointer_from_value */ /** * Invert a boolean value diff --git a/jerry-core/ecma/base/ecma-helpers-values-collection.c b/jerry-core/ecma/base/ecma-helpers-values-collection.c index 11d2c860c4..30bfdbbf76 100644 --- a/jerry-core/ecma/base/ecma-helpers-values-collection.c +++ b/jerry-core/ecma/base/ecma-helpers-values-collection.c @@ -28,8 +28,8 @@ /** * The type of ecma error and ecma collection chunk must be the same. */ -JERRY_STATIC_ASSERT (ECMA_TYPE_ERROR == ECMA_TYPE_COLLECTION_CHUNK, - ecma_type_error_must_be_the_same_as_ecma_type_collection_chunk); +JERRY_STATIC_ASSERT (ECMA_TYPE_ERROR == ECMA_TYPE_POINTER, + ecma_type_error_must_be_the_same_as_ecma_type_pointer); /** * Allocate a collection of ecma values. @@ -70,7 +70,7 @@ ecma_free_values_collection (ecma_collection_header_t *header_p, /**< collection { ecma_value_t *item_p = chunk_p->items; - JERRY_ASSERT (!ecma_is_value_collection_chunk (*item_p)); + JERRY_ASSERT (!ecma_is_value_pointer (*item_p)); do { @@ -83,9 +83,9 @@ ecma_free_values_collection (ecma_collection_header_t *header_p, /**< collection item_p++; } - while (!ecma_is_value_collection_chunk (*item_p)); + while (!ecma_is_value_pointer (*item_p)); - ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (*item_p); + ecma_collection_chunk_t *next_chunk_p = (ecma_collection_chunk_t *) ecma_get_pointer_from_value (*item_p); jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); @@ -122,21 +122,21 @@ ecma_append_to_values_collection (ecma_collection_header_t *header_p, /**< colle if (JERRY_UNLIKELY (item_index == 0)) { - JERRY_ASSERT (ecma_is_value_collection_chunk (chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS]) - && ecma_get_collection_chunk_from_value (chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS]) == NULL); + JERRY_ASSERT (ecma_is_value_pointer (chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS]) + && ecma_get_pointer_from_value (chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS]) == NULL); ecma_collection_chunk_t *next_chunk_p; next_chunk_p = (ecma_collection_chunk_t *) jmem_heap_alloc_block (sizeof (ecma_collection_chunk_t)); - chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS] = ecma_make_collection_chunk_value (next_chunk_p); + chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS] = ecma_make_pointer_value ((void *) next_chunk_p); ECMA_SET_POINTER (header_p->last_chunk_cp, next_chunk_p); chunk_p = next_chunk_p; } else { - JERRY_ASSERT (ecma_is_value_collection_chunk (chunk_p->items[item_index]) - && ecma_get_collection_chunk_from_value (chunk_p->items[item_index]) == NULL); + JERRY_ASSERT (ecma_is_value_pointer (chunk_p->items[item_index]) + && ecma_get_pointer_from_value (chunk_p->items[item_index]) == NULL); } } @@ -148,7 +148,7 @@ ecma_append_to_values_collection (ecma_collection_header_t *header_p, /**< colle } chunk_p->items[item_index] = value; - chunk_p->items[item_index + 1] = ecma_make_collection_chunk_value (NULL); + chunk_p->items[item_index + 1] = ecma_make_pointer_value (NULL); header_p->item_count++; } /* ecma_append_to_values_collection */ @@ -183,11 +183,11 @@ ecma_collection_iterator_next (ecma_value_t *ecma_value_p) /**< current value */ ecma_value_p++; - if (JERRY_UNLIKELY (ecma_is_value_collection_chunk (*ecma_value_p))) + if (JERRY_UNLIKELY (ecma_is_value_pointer (*ecma_value_p))) { - ecma_value_p = ecma_get_collection_chunk_from_value (*ecma_value_p)->items; + ecma_value_p = ((ecma_collection_chunk_t *) ecma_get_pointer_from_value (*ecma_value_p))->items; - JERRY_ASSERT (ecma_value_p == NULL || !ecma_is_value_collection_chunk (*ecma_value_p)); + JERRY_ASSERT (ecma_value_p == NULL || !ecma_is_value_pointer (*ecma_value_p)); return ecma_value_p; } diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 41e892ebe2..fffdf09b94 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -155,9 +155,10 @@ bool JERRY_ATTR_CONST ecma_is_value_float_number (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_number (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_string (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_direct_string (ecma_value_t value); +bool JERRY_ATTR_CONST ecma_is_value_non_direct_string (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_object (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_error_reference (ecma_value_t value); -bool JERRY_ATTR_CONST ecma_is_value_collection_chunk (ecma_value_t value); +bool JERRY_ATTR_CONST ecma_is_value_pointer (ecma_value_t value); void ecma_check_value_type_is_spec_defined (ecma_value_t value); @@ -171,14 +172,14 @@ ecma_value_t JERRY_ATTR_PURE ecma_make_string_value (const ecma_string_t *ecma_s ecma_value_t JERRY_ATTR_PURE ecma_make_magic_string_value (lit_magic_string_id_t id); ecma_value_t JERRY_ATTR_PURE ecma_make_object_value (const ecma_object_t *object_p); ecma_value_t JERRY_ATTR_PURE ecma_make_error_reference_value (const ecma_error_reference_t *error_ref_p); -ecma_value_t JERRY_ATTR_PURE ecma_make_collection_chunk_value (const ecma_collection_chunk_t *collection_chunk_p); +ecma_value_t JERRY_ATTR_PURE ecma_make_pointer_value (const void *any_p); ecma_integer_value_t JERRY_ATTR_CONST ecma_get_integer_from_value (ecma_value_t value); ecma_number_t JERRY_ATTR_PURE ecma_get_float_from_value (ecma_value_t value); ecma_number_t JERRY_ATTR_PURE ecma_get_number_from_value (ecma_value_t value); ecma_string_t JERRY_ATTR_PURE *ecma_get_string_from_value (ecma_value_t value); ecma_object_t JERRY_ATTR_PURE *ecma_get_object_from_value (ecma_value_t value); ecma_error_reference_t JERRY_ATTR_PURE *ecma_get_error_reference_from_value (ecma_value_t value); -ecma_collection_chunk_t JERRY_ATTR_PURE *ecma_get_collection_chunk_from_value (ecma_value_t value); +void * JERRY_ATTR_PURE ecma_get_pointer_from_value (ecma_value_t value); ecma_value_t JERRY_ATTR_CONST ecma_invert_boolean_value (ecma_value_t value); ecma_value_t ecma_copy_value (ecma_value_t value); ecma_value_t ecma_fast_copy_value (ecma_value_t value); 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 37a90bb6c7..1339e915cd 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h @@ -191,12 +191,20 @@ OBJECT_VALUE (LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) #endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + #ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN OBJECT_VALUE (LIT_MAGIC_STRING_PROMISE_UL, ECMA_BUILTIN_ID_PROMISE, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) #endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN +/* ECMA-262 v6, 23.1.1.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_MAP_UL, + ECMA_BUILTIN_ID_MAP, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ + /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c new file mode 100644 index 0000000000..820fc69877 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c @@ -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. + */ + +#include "ecma-map-object.h" + +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-map-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID map_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup map ECMA Map object built-in + * @{ + */ + +/** + * The Map.prototype object's 'clear' routine + * + * See also: + * ECMA-262 v6, 23.1.3.1 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_map_prototype_object_clear (ecma_value_t this_arg) /**< this argument */ +{ + return ecma_op_map_clear (this_arg); +} /* ecma_builtin_map_prototype_object_clear */ + +/** + * The Map.prototype object's 'delete' routine + * + * See also: + * ECMA-262 v6, 23.1.3.3 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_map_prototype_object_delete (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + return ecma_op_map_delete (this_arg, key_arg); +} /* ecma_builtin_map_prototype_object_delete */ + +/** + * The Map.prototype object's 'get' routine + * + * See also: + * ECMA-262 v6, 23.1.3.6 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +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_map_get (this_arg, key_arg); +} /* ecma_builtin_map_prototype_object_get */ + +/** + * The Map.prototype object's 'has' routine + * + * See also: + * ECMA-262 v6, 23.1.3.7 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_map_prototype_object_has (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + return ecma_op_map_has (this_arg, key_arg); +} /* ecma_builtin_map_prototype_object_has */ + +/** + * The Map.prototype object's 'set' routine + * + * See also: + * ECMA-262 v6, 23.1.3.9 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_map_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_map_set (this_arg, key_arg, value_arg); +} /* ecma_builtin_map_prototype_object_set */ + +/** + * The Map.prototype object's 'size' getter + * + * See also: + * ECMA-262 v6, 23.1.3.10 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_map_prototype_object_size_getter (ecma_value_t this_arg) /**< this argument */ +{ + return ecma_op_map_size (this_arg); +} /* ecma_builtin_map_prototype_object_size_getter */ + +/** + * @} + * @} + * @} + */ + +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.inc.h new file mode 100644 index 0000000000..41001a879e --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.inc.h @@ -0,0 +1,52 @@ +/* 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. + */ + +/* + * Map.prototype built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.1.3.2 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_MAP, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) + +/* ECMA-262 v6, 23.1.3 */ +STRING_VALUE (LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_MAP_UL, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_MAGIC_STRING_CLEAR, ecma_builtin_map_prototype_object_clear, 0, 0) +ROUTINE (LIT_MAGIC_STRING_DELETE, ecma_builtin_map_prototype_object_delete, 1, 1) +ROUTINE (LIT_MAGIC_STRING_GET, ecma_builtin_map_prototype_object_get, 1, 1) +ROUTINE (LIT_MAGIC_STRING_HAS, ecma_builtin_map_prototype_object_has, 1, 1) +ROUTINE (LIT_MAGIC_STRING_SET, ecma_builtin_map_prototype_object_set, 2, 2) + +/* ECMA-262 v6, 23.1.3.10 */ +ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_SIZE, + ecma_builtin_map_prototype_object_size_getter, + ECMA_PROPERTY_FIXED) + +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map.c b/jerry-core/ecma/builtin-objects/ecma-builtin-map.c new file mode 100644 index 0000000000..084f4350dc --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map.c @@ -0,0 +1,71 @@ +/* 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-map-object.h" + +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-map.inc.h" +#define BUILTIN_UNDERSCORED_ID map +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup map ECMA Map object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in Map object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_map_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 Map requires 'new'.")); +} /* ecma_builtin_map_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in Map object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_map_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_op_map_create (arguments_list_p, arguments_list_len); +} /* ecma_builtin_map_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h new file mode 100644 index 0000000000..7869fff407 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map.inc.h @@ -0,0 +1,42 @@ +/* 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. + */ + +/* + * Map built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + +/* Number properties: + * (property name, number value, writable, enumerable, configurable) */ + +/* ECMA-262 v6, 23.1.2 */ +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 0, + ECMA_PROPERTY_FIXED) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.1.2.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_MAP_PROTOTYPE, + ECMA_PROPERTY_FIXED) + +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ + +#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 d557f573b9..70561152f7 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -423,6 +423,24 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_PROMISE, #endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + +/* The Map prototype object (23.1.3) */ +BUILTIN (ECMA_BUILTIN_ID_MAP_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + map_prototype) + +/* The Map routine (ECMA-262 v6, 23.1.1.1) */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_MAP, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + map) + +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ + /* The Global object (15.1) */ BUILTIN (ECMA_BUILTIN_ID_GLOBAL, ECMA_OBJECT_TYPE_GENERAL, diff --git a/jerry-core/ecma/operations/ecma-map-object.c b/jerry-core/ecma/operations/ecma-map-object.c new file mode 100644 index 0000000000..f1a1d25b5b --- /dev/null +++ b/jerry-core/ecma/operations/ecma-map-object.c @@ -0,0 +1,586 @@ +/* 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-gc.h" +#include "ecma-helpers.h" +#include "ecma-map-object.h" +#include "ecma-objects.h" + +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup \addtogroup ecmamaphelpers ECMA builtin map helper functions + * @{ + */ + +JERRY_STATIC_ASSERT (ECMA_MAP_OBJECT_ITEM_COUNT == 3, + ecma_map_object_item_count_must_be_3); + +/** + * Handle calling [[Construct]] of built-in map like objects + * + * @return ecma value + */ +ecma_value_t +ecma_op_map_create (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); + + ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_MAP_PROTOTYPE); + ecma_object_t *object_p = ecma_create_object (prototype_obj_p, + sizeof (ecma_map_object_t), + ECMA_OBJECT_TYPE_CLASS); + + ecma_deref_object (prototype_obj_p); + + ecma_map_object_t *map_object_p = (ecma_map_object_t *) object_p; + map_object_p->header.u.class_prop.class_id = LIT_MAGIC_STRING_MAP_UL; + map_object_p->header.u.class_prop.extra_info = 0; + map_object_p->header.u.class_prop.u.length = 0; + map_object_p->first_chunk_cp = ECMA_NULL_POINTER; + map_object_p->last_chunk_cp = ECMA_NULL_POINTER; + + return ecma_make_object_value (object_p); +} /* ecma_op_map_create */ + +/** + * Get map 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 if this_arg is a valid map object + * NULL otherwise + */ +static ecma_map_object_t * +ecma_op_map_get_object (ecma_value_t this_arg) /**< this argument */ +{ + 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); + + if (ecma_get_object_type (&map_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS + && map_object_p->header.u.class_prop.class_id == LIT_MAGIC_STRING_MAP_UL) + { + return map_object_p; + } + } + + ecma_raise_type_error (ECMA_ERR_MSG ("Expected a Map object.")); + return NULL; +} /* ecma_op_map_get_object */ + +/** + * Returns with the size of the map object. + * + * @return size of the map object as ecma-value. + */ +ecma_value_t +ecma_op_map_size (ecma_value_t this_arg) /**< this argument */ +{ + ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + if (map_object_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + return ecma_make_uint32_value (map_object_p->header.u.class_prop.u.length); +} /* ecma_op_map_size */ + +/** + * Linear search for the value in the map storage + * + * @return pointer to value if key is found + * NULL otherwise + */ +static ecma_value_t * +ecma_builtin_map_search (jmem_cpointer_t first_chunk_cp, /**< first chunk */ + ecma_value_t key) /**< key to search */ +{ + if (JERRY_UNLIKELY (first_chunk_cp == ECMA_NULL_POINTER)) + { + return NULL; + } + + ecma_map_object_chunk_t *chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t, + first_chunk_cp); + + bool is_direct = true; + const ecma_string_t *key_str_p = NULL; + ecma_number_t key_float = 0; + + if (ecma_is_value_non_direct_string (key)) + { + key_str_p = ecma_get_string_from_value (key); + is_direct = false; + } + else if (ecma_is_value_float_number (key)) + { + key_float = ecma_get_float_from_value (key); + is_direct = false; + } + + ecma_value_t *item_p = chunk_p->items; + ecma_value_t last_key = ECMA_VALUE_ARRAY_HOLE; + + while (true) + { + ecma_value_t item = *item_p++; + + if (JERRY_UNLIKELY (item == ECMA_VALUE_ARRAY_HOLE)) + { + JERRY_ASSERT (last_key == ECMA_VALUE_ARRAY_HOLE); + continue; + } + + if (JERRY_UNLIKELY (ecma_is_value_pointer (item))) + { + item_p = (ecma_value_t *) ecma_get_pointer_from_value (item); + + if (item_p == NULL) + { + JERRY_ASSERT (last_key == ECMA_VALUE_ARRAY_HOLE); + return NULL; + } + + JERRY_ASSERT (!ecma_is_value_pointer (*item_p)); + continue; + } + + if (last_key == ECMA_VALUE_ARRAY_HOLE) + { + last_key = item; + } + else + { + if (JERRY_LIKELY (is_direct)) + { + if (key == last_key) + { + return item_p - 1; + } + } + else if (key_str_p != NULL) + { + if (ecma_is_value_non_direct_string (last_key) + && ecma_compare_ecma_non_direct_strings (key_str_p, ecma_get_string_from_value (last_key))) + { + return item_p - 1; + } + } + else if (ecma_is_value_float_number (last_key) + && ecma_get_float_from_value (last_key) == key_float) + { + return item_p - 1; + } + + last_key = ECMA_VALUE_ARRAY_HOLE; + } + } +} /* ecma_builtin_map_search */ + +/** + * The generic map prototype object's 'get' routine + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_op_map_get (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + if (map_object_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t *value_p = ecma_builtin_map_search (map_object_p->first_chunk_cp, key_arg); + + if (value_p == NULL) + { + return ECMA_VALUE_UNDEFINED; + } + + return ecma_copy_value (*value_p); +} /* ecma_op_map_get */ + +/** + * The generic map prototype object's 'has' routine + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_op_map_has (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + if (map_object_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + return ecma_make_boolean_value (ecma_builtin_map_search (map_object_p->first_chunk_cp, key_arg) != NULL); +} /* ecma_op_map_has */ + +/** + * The generic map prototype object's 'set' routine + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_op_map_set (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg, /**< key argument */ + ecma_value_t value_arg) /**< value argument */ +{ + ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + if (map_object_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + ecma_value_t *value_p = ecma_builtin_map_search (map_object_p->first_chunk_cp, key_arg); + + if (value_p == NULL) + { + ecma_value_t *key_p = NULL; + ecma_map_object_chunk_t *last_chunk_p = ECMA_GET_POINTER (ecma_map_object_chunk_t, + map_object_p->last_chunk_cp); + + if (last_chunk_p != NULL) + { + if (last_chunk_p->items[2] == ECMA_VALUE_ARRAY_HOLE) + { + key_p = last_chunk_p->items + 2; + + if (last_chunk_p->items[1] == ECMA_VALUE_ARRAY_HOLE) + { + key_p = last_chunk_p->items + 1; + value_p = last_chunk_p->items + 2; + } + } + } + + if (key_p == NULL || value_p == NULL) + { + size_t size = sizeof (ecma_map_object_chunk_t); + ecma_map_object_chunk_t *new_chunk_p = (ecma_map_object_chunk_t *) jmem_heap_alloc_block (size); + + new_chunk_p->items[ECMA_MAP_OBJECT_ITEM_COUNT] = ecma_make_pointer_value (NULL); + + for (int i = 0; i < ECMA_MAP_OBJECT_ITEM_COUNT; i++) + { + new_chunk_p->items[i] = ECMA_VALUE_ARRAY_HOLE; + } + + ECMA_SET_NON_NULL_POINTER (map_object_p->last_chunk_cp, new_chunk_p); + + if (last_chunk_p == NULL) + { + map_object_p->first_chunk_cp = map_object_p->last_chunk_cp; + } + else + { + last_chunk_p->items[ECMA_MAP_OBJECT_ITEM_COUNT] = ecma_make_pointer_value (new_chunk_p); + } + + if (key_p == NULL) + { + JERRY_ASSERT (value_p == NULL); + key_p = new_chunk_p->items + 0; + value_p = new_chunk_p->items + 1; + } + else + { + value_p = new_chunk_p->items + 0; + } + } + + *key_p = ecma_copy_value_if_not_object (key_arg); + map_object_p->header.u.class_prop.u.length++; + } + else + { + ecma_free_value_if_not_object (*value_p); + } + + *value_p = ecma_copy_value_if_not_object (value_arg); + + ecma_ref_object (&map_object_p->header.object); + return this_arg; +} /* ecma_op_map_set */ + +/** + * Low-level function to clear all items from a map + */ +void +ecma_op_map_clear_map (ecma_map_object_t *map_object_p) /**< map object */ +{ + JERRY_ASSERT (ecma_get_object_type (&map_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS + && (map_object_p->header.u.class_prop.class_id == LIT_MAGIC_STRING_MAP_UL)); + + jmem_cpointer_t first_chunk_cp = map_object_p->first_chunk_cp; + + if (JERRY_UNLIKELY (first_chunk_cp == ECMA_NULL_POINTER)) + { + return; + } + + ecma_map_object_chunk_t *chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t, + first_chunk_cp); + + do + { + ecma_value_t *current_p = chunk_p->items; + ecma_value_t *last_p = current_p + ECMA_MAP_OBJECT_ITEM_COUNT; + + do + { + ecma_free_value_if_not_object (*current_p++); + } + while (current_p < last_p); + + ecma_value_t next = *current_p; + + jmem_heap_free_block (chunk_p, sizeof (ecma_map_object_chunk_t)); + + chunk_p = (ecma_map_object_chunk_t *) ecma_get_pointer_from_value (next); + } + while (chunk_p != NULL); + + map_object_p->header.u.class_prop.u.length = 0; + map_object_p->first_chunk_cp = ECMA_NULL_POINTER; + map_object_p->last_chunk_cp = ECMA_NULL_POINTER; +} /* ecma_op_map_clear_map */ + +/** + * The Map prototype object's 'clear' routine + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_op_map_clear (ecma_value_t this_arg) /**< this argument */ +{ + /* WeakMap does not have a clear method. */ + ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + if (map_object_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + ecma_op_map_clear_map (map_object_p); + return ECMA_VALUE_UNDEFINED; +} /* ecma_op_map_clear */ + +/** + * Deletes the current chunk if it is filled with ECMA_VALUE_ARRAY_HOLE. + * + * @return next chunk if the chunk is deleted, NULL otherwise + */ +static ecma_map_object_chunk_t * +ecma_op_map_delete_chunk (ecma_map_object_t *map_object_p, /**< map object */ + ecma_map_object_chunk_t *chunk_p, /**< current chunk */ + ecma_map_object_chunk_t *prev_chunk_p) /**< previous chunk */ +{ + for (int i = 0; i < ECMA_MAP_OBJECT_ITEM_COUNT; i++) + { + JERRY_ASSERT (!ecma_is_value_pointer (chunk_p->items[i])); + + if (chunk_p->items[i] != ECMA_VALUE_ARRAY_HOLE) + { + return NULL; + } + } + + ecma_value_t next_chunk = chunk_p->items[ECMA_MAP_OBJECT_ITEM_COUNT]; + ecma_map_object_chunk_t *next_chunk_p = (ecma_map_object_chunk_t *) ecma_get_pointer_from_value (next_chunk); + + jmem_heap_free_block (chunk_p, sizeof (ecma_map_object_chunk_t)); + + if (prev_chunk_p != NULL) + { + prev_chunk_p->items[ECMA_MAP_OBJECT_ITEM_COUNT] = ecma_make_pointer_value (next_chunk_p); + + if (next_chunk_p == NULL) + { + JERRY_ASSERT (map_object_p->first_chunk_cp != map_object_p->last_chunk_cp); + JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t, map_object_p->last_chunk_cp) == chunk_p); + + ECMA_SET_POINTER (map_object_p->last_chunk_cp, prev_chunk_p); + } + return next_chunk_p; + } + + if (next_chunk_p == NULL) + { + JERRY_ASSERT (map_object_p->first_chunk_cp == map_object_p->last_chunk_cp); + JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t, map_object_p->last_chunk_cp) == chunk_p); + + map_object_p->first_chunk_cp = ECMA_NULL_POINTER; + map_object_p->last_chunk_cp = ECMA_NULL_POINTER; + return next_chunk_p; + } + + ECMA_SET_POINTER (map_object_p->first_chunk_cp, next_chunk_p); + return next_chunk_p; +} /* ecma_op_map_delete_chunk */ + +/** + * The generic map prototype object's 'delete' routine + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_op_map_delete (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ +{ + ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + if (map_object_p == NULL) + { + return ECMA_VALUE_ERROR; + } + + if (JERRY_UNLIKELY (map_object_p->first_chunk_cp == ECMA_NULL_POINTER)) + { + return ECMA_VALUE_FALSE; + } + + ecma_map_object_chunk_t *chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_map_object_chunk_t, + map_object_p->first_chunk_cp); + + bool is_direct = true; + const ecma_string_t *key_str_p = NULL; + ecma_number_t key_float = 0; + + if (ecma_is_value_non_direct_string (key_arg)) + { + key_str_p = ecma_get_string_from_value (key_arg); + is_direct = false; + } + else if (ecma_is_value_float_number (key_arg)) + { + key_float = ecma_get_float_from_value (key_arg); + is_direct = false; + } + + ecma_map_object_chunk_t *prev_chunk_p = NULL; + ecma_value_t *item_p = chunk_p->items; + bool is_key = true; + + while (true) + { + ecma_value_t item = *item_p++; + + if (JERRY_UNLIKELY (item == ECMA_VALUE_ARRAY_HOLE)) + { + JERRY_ASSERT (is_key); + continue; + } + + if (JERRY_UNLIKELY (ecma_is_value_pointer (item))) + { + prev_chunk_p = chunk_p; + chunk_p = (ecma_map_object_chunk_t *) ecma_get_pointer_from_value (item); + + if (chunk_p == NULL) + { + JERRY_ASSERT (is_key); + return ECMA_VALUE_FALSE; + } + + item_p = chunk_p->items; + + JERRY_ASSERT (!ecma_is_value_pointer (*item_p)); + continue; + } + + if (is_key) + { + if (JERRY_LIKELY (is_direct)) + { + if (key_arg == item) + { + break; + } + } + else if (key_str_p != NULL) + { + if (ecma_is_value_non_direct_string (item) + && ecma_compare_ecma_non_direct_strings (key_str_p, ecma_get_string_from_value (item))) + { + break; + } + } + else if (ecma_is_value_float_number (item) + && ecma_get_float_from_value (item) == key_float) + { + break; + } + } + + is_key = !is_key; + } + + map_object_p->header.u.class_prop.u.length--; + + item_p -= 1; + ecma_free_value_if_not_object (item_p[0]); + item_p[0] = ECMA_VALUE_ARRAY_HOLE; + + if ((item_p - chunk_p->items) < ECMA_MAP_OBJECT_ITEM_COUNT - 1) + { + JERRY_ASSERT (!ecma_is_value_pointer (item_p[1])); + + ecma_free_value_if_not_object (item_p[1]); + item_p[1] = ECMA_VALUE_ARRAY_HOLE; + + ecma_op_map_delete_chunk (map_object_p, chunk_p, prev_chunk_p); + return ECMA_VALUE_TRUE; + } + + ecma_map_object_chunk_t *next_chunk_p = ecma_op_map_delete_chunk (map_object_p, chunk_p, prev_chunk_p); + + if (next_chunk_p == NULL) + { + prev_chunk_p = chunk_p; + + ecma_value_t next_chunk = chunk_p->items[ECMA_MAP_OBJECT_ITEM_COUNT]; + next_chunk_p = (ecma_map_object_chunk_t *) ecma_get_pointer_from_value (next_chunk); + } + + ecma_free_value_if_not_object (next_chunk_p->items[0]); + next_chunk_p->items[0] = ECMA_VALUE_ARRAY_HOLE; + + ecma_op_map_delete_chunk (map_object_p, next_chunk_p, prev_chunk_p); + + return ECMA_VALUE_TRUE; +} /* ecma_op_map_delete */ + +/** + * @} + * @} + */ + +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ diff --git a/jerry-core/ecma/operations/ecma-map-object.h b/jerry-core/ecma/operations/ecma-map-object.h new file mode 100644 index 0000000000..fd3ddba1c7 --- /dev/null +++ b/jerry-core/ecma/operations/ecma-map-object.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. + */ + +#ifndef ECMA_MAP_OBJECT_H +#define ECMA_MAP_OBJECT_H + +#include "ecma-globals.h" + +#ifndef CONFIG_DISABLE_ES2015_MAP_BUILTIN + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmamaphelpers ECMA builtin map helper functions + * @{ + */ + +ecma_value_t ecma_op_map_create (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); +ecma_value_t ecma_op_map_size (ecma_value_t this_arg); +ecma_value_t ecma_op_map_get (ecma_value_t this_arg, ecma_value_t key_arg); +ecma_value_t ecma_op_map_has (ecma_value_t this_arg, ecma_value_t key_arg); +ecma_value_t ecma_op_map_set (ecma_value_t this_arg, ecma_value_t key_arg, ecma_value_t value_arg); +void ecma_op_map_clear_map (ecma_map_object_t *map_object_p); +ecma_value_t ecma_op_map_clear (ecma_value_t this_arg); +ecma_value_t ecma_op_map_delete (ecma_value_t this_arg, ecma_value_t key_arg); + +/** + * @} + * @} + */ + +#endif /* !CONFIG_DISABLE_ES2015_MAP_BUILTIN */ + +#endif /* !ECMA_MAP_OBJECT_H */ diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 143c40546a..b21a4a883d 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -38,6 +38,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_OF, "of") #if !defined (CONFIG_DISABLE_MATH_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LN2_U, "LN2") #endif +#if !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MAP_UL, "Map") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NAN, "NaN") #if !defined (CONFIG_DISABLE_DATE_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UTC_U, "UTC") @@ -53,6 +56,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COS, "cos") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EXP, "exp") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET, "get") +#if !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_HAS, "has") +#endif #if !defined (CONFIG_DISABLE_MATH_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LOG, "log") #endif @@ -122,6 +128,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PUSH, "push") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RACE, "race") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SEAL, "seal") +#if !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SIZE, "size") +#endif #if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) \ || !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SOME, "some") @@ -153,6 +162,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ATAN2, "atan2") #if !defined (CONFIG_DISABLE_ES2015_PROMISE_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CATCH, "catch") #endif +#if !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CLEAR, "clear") +#endif #if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) \ || !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EVERY, "every") @@ -211,6 +223,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CHAR_AT_UL, "charAt") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CONCAT, "concat") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CREATE, "create") +#if !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DELETE, "delete") +#endif #if !defined (CONFIG_DISABLE_ANNEXB_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ESCAPE, "escape") #endif @@ -541,11 +556,15 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_PI_U) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_OF) #elif !defined (CONFIG_DISABLE_MATH_BUILTIN) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (2, LIT_MAGIC_STRING_LN2_U) +#elif !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN) +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 !defined (CONFIG_DISABLE_MATH_BUILTIN) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (3, LIT_MAGIC_STRING_LN2_U) +#elif !defined (CONFIG_DISABLE_ES2015_MAP_BUILTIN) +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) #endif diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index bdd810ea0c..d1c5134e98 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -33,6 +33,7 @@ LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR = "]" LIT_MAGIC_STRING_PI_U = "PI" LIT_MAGIC_STRING_OF = "of" LIT_MAGIC_STRING_LN2_U = "LN2" +LIT_MAGIC_STRING_MAP_UL = "Map" LIT_MAGIC_STRING_NAN = "NaN" LIT_MAGIC_STRING_UTC_U = "UTC" LIT_MAGIC_STRING_ABS = "abs" @@ -40,6 +41,7 @@ LIT_MAGIC_STRING_ALL = "all" LIT_MAGIC_STRING_COS = "cos" LIT_MAGIC_STRING_EXP = "exp" LIT_MAGIC_STRING_GET = "get" +LIT_MAGIC_STRING_HAS = "has" LIT_MAGIC_STRING_LOG = "log" LIT_MAGIC_STRING_MAP = "map" LIT_MAGIC_STRING_MAX = "max" @@ -73,6 +75,7 @@ LIT_MAGIC_STRING_NULL = "null" LIT_MAGIC_STRING_PUSH = "push" LIT_MAGIC_STRING_RACE = "race" LIT_MAGIC_STRING_SEAL = "seal" +LIT_MAGIC_STRING_SIZE = "size" LIT_MAGIC_STRING_SOME = "some" LIT_MAGIC_STRING_SORT = "sort" LIT_MAGIC_STRING_SQRT = "sqrt" @@ -87,6 +90,7 @@ LIT_MAGIC_STRING_SQRT2_U = "SQRT2" LIT_MAGIC_STRING_APPLY = "apply" LIT_MAGIC_STRING_ATAN2 = "atan2" LIT_MAGIC_STRING_CATCH = "catch" +LIT_MAGIC_STRING_CLEAR = "clear" LIT_MAGIC_STRING_EVERY = "every" LIT_MAGIC_STRING_FALSE = "false" LIT_MAGIC_STRING_FLOOR = "floor" @@ -111,6 +115,7 @@ LIT_MAGIC_STRING_CALLER = "caller" LIT_MAGIC_STRING_CHAR_AT_UL = "charAt" LIT_MAGIC_STRING_CONCAT = "concat" LIT_MAGIC_STRING_CREATE = "create" +LIT_MAGIC_STRING_DELETE = "delete" LIT_MAGIC_STRING_ESCAPE = "escape" LIT_MAGIC_STRING_FILTER = "filter" LIT_MAGIC_STRING_FREEZE = "freeze" diff --git a/jerry-core/profiles/README.md b/jerry-core/profiles/README.md index ec576048f3..f6723f0c85 100644 --- a/jerry-core/profiles/README.md +++ b/jerry-core/profiles/README.md @@ -87,6 +87,8 @@ In JerryScript all of the features are enabled by default, so an empty profile f Disable the built-in updates of the 5.1 standard. There are some differences in those built-ins which available in both [5.1](http://www.ecma-international.org/ecma-262/5.1/) and [2015](http://www.ecma-international.org/ecma-262/6.0/) versions of the standard. JerryScript uses the latest definition by default. * `CONFIG_DISABLE_ES2015_CLASS`: Disable the [class](https://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions) language element. +* `CONFIG_DISABLE_ES2015_MAP_BUILTIN`: + Disable the [Map](http://www.ecma-international.org/ecma-262/6.0/#sec-keyed-collection) built-ins. * `CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER`: Disable the [enhanced object initializer](http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer) language element. * `CONFIG_DISABLE_ES2015_PROMISE_BUILTIN`: diff --git a/jerry-core/vm/vm-stack.c b/jerry-core/vm/vm-stack.c index 9b8400b114..6284c0878c 100644 --- a/jerry-core/vm/vm-stack.c +++ b/jerry-core/vm/vm-stack.c @@ -85,9 +85,10 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ { ecma_value_t value = chunk_p->items[index]; - if (JERRY_UNLIKELY (ecma_is_value_collection_chunk (value))) + if (JERRY_UNLIKELY (ecma_is_value_pointer (value))) { - ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (value); + ecma_collection_chunk_t *next_chunk_p; + next_chunk_p = (ecma_collection_chunk_t *) ecma_get_pointer_from_value (value); jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); chunk_p = next_chunk_p; diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index fbdbb46002..70a2cdf813 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -2411,12 +2411,12 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ uint32_t index = context_top_p[-3]; - JERRY_ASSERT (!ecma_is_value_collection_chunk (chunk_p->items[index])); + JERRY_ASSERT (!ecma_is_value_pointer (chunk_p->items[index])); *stack_top_p++ = chunk_p->items[index]; index++; - if (JERRY_LIKELY (!ecma_is_value_collection_chunk (chunk_p->items[index]))) + if (JERRY_LIKELY (!ecma_is_value_pointer (chunk_p->items[index]))) { context_top_p[-3] = index; continue; @@ -2424,7 +2424,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ context_top_p[-3] = 0; - ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (chunk_p->items[index]); + ecma_collection_chunk_t *next_chunk_p; + next_chunk_p = (ecma_collection_chunk_t *) ecma_get_pointer_from_value (chunk_p->items[index]); ECMA_SET_INTERNAL_VALUE_ANY_POINTER (context_top_p[-2], next_chunk_p); jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); @@ -2462,7 +2463,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ index++; ecma_value_t value = chunk_p->items[index]; - if (JERRY_LIKELY (!ecma_is_value_collection_chunk (value))) + if (JERRY_LIKELY (!ecma_is_value_pointer (value))) { stack_top_p[-3] = index; } @@ -2471,7 +2472,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ index = 0; stack_top_p[-3] = 0; - ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (value); + ecma_collection_chunk_t *next_chunk_p; + next_chunk_p = (ecma_collection_chunk_t *) ecma_get_pointer_from_value (value); ECMA_SET_INTERNAL_VALUE_ANY_POINTER (stack_top_p[-2], next_chunk_p); jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); diff --git a/tests/jerry/es2015/map.js b/tests/jerry/es2015/map.js new file mode 100644 index 0000000000..05ac0b8348 --- /dev/null +++ b/tests/jerry/es2015/map.js @@ -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. + */ + +var m = new Map(); +assert(m.size == 0); +assert(m.set(1, 1) === m); +assert(m.has(1)); +assert(m.size == 1); + +assert(m.set(undefined, 123) === m); +assert(m.size == 2); +assert(m.has(undefined)); +assert(m.get(undefined) === 123); + +assert(m.set(null, 456) === m); +assert(m.size == 3); +assert(m.has(null)); +assert(m.get(null) === 456); + +assert(m.set("strItem", { x:789 }) === m); +assert(m.size == 4); +assert(m.has("str" + "Item")); +assert(m.get("st" + "rItem").x === 789); + +assert(m.set(12.25, 12.25) === m); +assert(m.size == 5); +assert(m.has(12 + (function() { return 0.25 })())); +assert(m.get(13 - (function() { return 0.75 })()) === 12.25); + +assert(m.delete(1)) +assert(m.size == 4); +assert(!m.has(1)); +assert(m.get(1) === undefined); + +assert(!m.delete(2)); + +assert(m.delete(12 + (function() { return 0.25 })())); +assert(m.size == 3); +assert(!m.has(12.25)); +assert(m.get(12.25) === undefined); + +assert(m.delete("strI" + "tem")) +assert(m.delete(undefined)) +assert(m.size == 1); + +assert(m.delete(null)) +assert(m.size == 0); + +m.set(1,1) +m.set(2,2) +m.set(3,3) +m.set(1,7) +m.set(1,8) +m.set(2,7) +m.set(2,8) +m.set(3,7) +m.set(3,8) + +assert(m.size == 3); +assert(m.get(1) === 8); +assert(m.get(2) === 8); +assert(m.get(3) === 8);