From 129ca4946c981cc6349fae2eb875c5b34ef77049 Mon Sep 17 00:00:00 2001 From: kisbg Date: Mon, 1 Mar 2021 12:46:54 +0000 Subject: [PATCH] Implement WeakRef Object (#4546) Related test262 test-cases has been removed from skip list. Execpt two test-case since they need other feature to work (Finalization registry and async GC) JerryScript-DCO-1.0-Signed-off-by: Bence Gabor Kis kisbg@inf.u-szeged.hu --- docs/02.API-REFERENCE.md | 1 + jerry-core/CMakeLists.txt | 4 + jerry-core/api/jerry.c | 9 ++ jerry-core/config.h | 9 ++ jerry-core/ecma/base/ecma-gc.c | 28 +++++- jerry-core/ecma/base/ecma-globals.h | 2 +- .../builtin-objects/ecma-builtin-global.inc.h | 10 +- .../ecma-builtin-weakref-prototype.c | 72 ++++++++++++++ .../ecma-builtin-weakref-prototype.inc.h | 41 ++++++++ .../builtin-objects/ecma-builtin-weakref.c | 97 +++++++++++++++++++ .../ecma-builtin-weakref.inc.h | 44 +++++++++ .../ecma/builtin-objects/ecma-builtins.inc.h | 20 +++- .../ecma/operations/ecma-container-object.c | 77 +-------------- .../ecma/operations/ecma-container-object.h | 1 - jerry-core/ecma/operations/ecma-objects.c | 79 +++++++++++++++ jerry-core/ecma/operations/ecma-objects.h | 4 + jerry-core/include/jerryscript-core.h | 2 + jerry-core/lit/lit-magic-strings.h | 1 + jerry-core/lit/lit-magic-strings.inc.h | 7 ++ jerry-core/lit/lit-magic-strings.ini | 2 + jerry-core/profiles/README.md | 2 + tests/jerry/es.next/weakref.js | 69 +++++++++++++ tests/test262-esnext-excludelist.xml | 25 ----- tests/unit-core/test-api-objecttype.c | 2 + 24 files changed, 500 insertions(+), 108 deletions(-) create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakref-prototype.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakref-prototype.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakref.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-weakref.inc.h create mode 100644 tests/jerry/es.next/weakref.js diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 26f025415..0189ce5fb 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -57,6 +57,7 @@ Enum that contains JerryScript **object** value types: - JERRY_OBJECT_TYPE_SYMBOL - Symbol object - JERRY_OBJECT_TYPE_GENERATOR - Generator object - JERRY_OBJECT_TYPE_BIGINT - BigInt object + - JERRY_OBJECT_TYPE_WEAKREF - WeakRef object *New in version 2.4*. diff --git a/jerry-core/CMakeLists.txt b/jerry-core/CMakeLists.txt index 442fe94ca..5d9d00cd1 100644 --- a/jerry-core/CMakeLists.txt +++ b/jerry-core/CMakeLists.txt @@ -220,6 +220,8 @@ set(SOURCE_CORE_FILES ecma/builtin-objects/ecma-builtin-urierror.c ecma/builtin-objects/ecma-builtin-weakmap-prototype.c ecma/builtin-objects/ecma-builtin-weakmap.c + ecma/builtin-objects/ecma-builtin-weakref-prototype.c + ecma/builtin-objects/ecma-builtin-weakref.c ecma/builtin-objects/ecma-builtin-weakset-prototype.c ecma/builtin-objects/ecma-builtin-weakset.c ecma/builtin-objects/ecma-builtins.c @@ -408,6 +410,8 @@ if(ENABLE_AMALGAM) ecma/builtin-objects/ecma-builtin-urierror.inc.h ecma/builtin-objects/ecma-builtin-weakmap-prototype.inc.h ecma/builtin-objects/ecma-builtin-weakmap.inc.h + ecma/builtin-objects/ecma-builtin-weakref-prototype.inc.h + ecma/builtin-objects/ecma-builtin-weakref.inc.h ecma/builtin-objects/ecma-builtin-weakset-prototype.inc.h ecma/builtin-objects/ecma-builtin-weakset.inc.h ecma/builtin-objects/ecma-builtins-internal.h diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 368e42101..49152c1b0 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -1237,6 +1237,12 @@ jerry_object_get_type (const jerry_value_t value) /**< input value to check */ return JERRY_OBJECT_TYPE_CONTAINER; } #endif /* JERRY_BUILTIN_CONTAINER */ +#if JERRY_BUILTIN_WEAKREF + case LIT_MAGIC_STRING_WEAKREF_UL: + { + return JERRY_OBJECT_TYPE_WEAKREF; + } +#endif /* JERRY_BUILTIN_WEAKREF */ default: { break; @@ -1460,6 +1466,9 @@ jerry_is_feature_enabled (const jerry_feature_t feature) /**< feature to check * #if JERRY_BUILTIN_WEAKMAP || feature == JERRY_FEATURE_WEAKMAP #endif /* JERRY_BUILTIN_WEAKMAP */ +#if JERRY_BUILTIN_WEAKREF + || feature == JERRY_FEATURE_WEAKREF +#endif /* JERRY_BUILTIN_WEAKREF */ #if JERRY_BUILTIN_WEAKSET || feature == JERRY_FEATURE_WEAKSET #endif /* JERRY_BUILTIN_WEAKSET */ diff --git a/jerry-core/config.h b/jerry-core/config.h index e21c4546b..10d191b8d 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -123,6 +123,10 @@ # define JERRY_BUILTIN_WEAKMAP JERRY_ESNEXT #endif /* !defined (JERRY_BUILTIN_WEAKMAP) */ +#ifndef JERRY_BUILTIN_WEAKREF +# define JERRY_BUILTIN_WEAKREF JERRY_ESNEXT +#endif /* !defined (JERRY_BUILTIN_WEAKREF) */ + #ifndef JERRY_BUILTIN_WEAKSET # define JERRY_BUILTIN_WEAKSET JERRY_ESNEXT #endif /* !defined (JERRY_BUILTIN_WEAKSET) */ @@ -568,6 +572,10 @@ || ((JERRY_BUILTIN_WEAKMAP != 0) && (JERRY_BUILTIN_WEAKMAP != 1)) # error "Invalid value for JERRY_BUILTIN_WEAKMAP macro." #endif +#if !defined (JERRY_BUILTIN_WEAKREF) \ +|| ((JERRY_BUILTIN_WEAKREF != 0) && (JERRY_BUILTIN_WEAKREF != 1)) +# error "Invalid value for JERRY_BUILTIN_WEAKREF macro." +#endif #if !defined (JERRY_BUILTIN_WEAKSET) \ || ((JERRY_BUILTIN_WEAKSET != 0) && (JERRY_BUILTIN_WEAKSET != 1)) # error "Invalid value for JERRY_BUILTIN_WEAKSET macro." @@ -597,6 +605,7 @@ || (JERRY_BUILTIN_MAP == 1) \ || (JERRY_BUILTIN_SET == 1) \ || (JERRY_BUILTIN_WEAKMAP == 1) \ +|| (JERRY_BUILTIN_WEAKREF == 1) \ || (JERRY_BUILTIN_WEAKSET == 1) \ || (JERRY_BUILTIN_PROMISE == 1) \ || (JERRY_BUILTIN_PROXY == 1) \ diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 7db8e018a..5478a3db1 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -1382,7 +1382,7 @@ ecma_gc_free_properties (ecma_object_t *object_p) /**< object */ break; } #endif /* JERRY_ESNEXT */ -#if JERRY_BUILTIN_WEAKMAP || JERRY_BUILTIN_WEAKSET +#if JERRY_BUILTIN_WEAKMAP || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKREF case LIT_INTERNAL_MAGIC_STRING_WEAK_REFS: { ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, @@ -1392,17 +1392,23 @@ ecma_gc_free_properties (ecma_object_t *object_p) /**< object */ 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_object_t *obj_p = ecma_get_object_from_value (value); - ecma_op_container_remove_weak_entry (container_p, - ecma_make_object_value (object_p)); + if (ecma_object_class_is (obj_p, LIT_MAGIC_STRING_WEAKREF_UL)) + { + JERRY_ASSERT (ecma_object_class_is (obj_p, LIT_MAGIC_STRING_WEAKREF_UL)); + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + ext_obj_p->u.class_prop.u.target = ECMA_VALUE_UNDEFINED; + continue; + } + ecma_op_container_remove_weak_entry (obj_p, ecma_make_object_value (object_p)); } } ecma_collection_destroy (refs_p); break; } -#endif /* JERRY_BUILTIN_WEAKMAP || JERRY_BUILTIN_WEAKSET */ +#endif /* JERRY_BUILTIN_WEAKMAP || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKREF */ default: { JERRY_ASSERT (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); @@ -1641,6 +1647,18 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ break; } #endif /* JERRY_BUILTIN_PROMISE */ +#if JERRY_BUILTIN_WEAKREF + case LIT_MAGIC_STRING_WEAKREF_UL: + { + ecma_value_t target = ext_object_p->u.class_prop.u.target; + + if (!ecma_is_value_undefined (target)) + { + ecma_op_object_unref_weak (ecma_get_object_from_value (target), ecma_make_object_value (object_p)); + } + break; + } +#endif /* JERRY_BUILTIN_WEAKREF */ #if JERRY_BUILTIN_CONTAINER #if JERRY_BUILTIN_MAP case LIT_MAGIC_STRING_MAP_UL: diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index a0cb0a3aa..97d904fcf 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -959,7 +959,7 @@ typedef struct ecma_value_t date; /**< Date object [[DateValue]] internal property */ int32_t tza; /**< TimeZone adjustment for date objects */ uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */ - ecma_value_t target; /**< [[ProxyTarget]] internal property */ + ecma_value_t target; /**< [[ProxyTarget]] or [[WeakRefTarget]] internal property */ ecma_value_t head; /**< points to the async generator task queue head item */ ecma_value_t promise; /**< PromiseCapability[[Promise]] internal slot */ } u; 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 57f7f96e9..918c76157 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h @@ -233,14 +233,20 @@ OBJECT_VALUE (LIT_MAGIC_STRING_SET_UL, OBJECT_VALUE (LIT_MAGIC_STRING_WEAKMAP_UL, ECMA_BUILTIN_ID_WEAKMAP, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) -#endif /* JERRY_BUILTIN_SET */ +#endif /* JERRY_BUILTIN_WEAKMAP */ + +#if JERRY_BUILTIN_WEAKREF +OBJECT_VALUE (LIT_MAGIC_STRING_WEAKREF_UL, + ECMA_BUILTIN_ID_WEAKREF, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* JERRY_BUILTIN_WEAKREF */ #if JERRY_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 /* JERRY_BUILTIN_SET */ +#endif /* JERRY_BUILTIN_WEAKSET */ #if JERRY_ESNEXT /* ECMA-262 v6, 19.4.1.1 */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakref-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-weakref-prototype.c new file mode 100644 index 000000000..ae41617e5 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakref-prototype.c @@ -0,0 +1,72 @@ +/* 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" +#include "ecma-exceptions.h" + +#if JERRY_BUILTIN_WEAKREF + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +/** + * This object has a custom dispatch function. + */ +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-weakref-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID weakref_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup weakref ECMA WeakRef object built-in + * @{ + */ + + /** + * Deref checks weakRef target + * + * @return weakRef target + * error - otherwise + */ +static ecma_value_t +ecma_builtin_weakref_prototype_object_deref (ecma_value_t this_arg) /**< this argument */ +{ + if (!ecma_is_value_object (this_arg)) + { + return ecma_raise_type_error ("Target is not Object"); + } + + ecma_object_t *object_p = ecma_get_object_from_value (this_arg); + ecma_extended_object_t *this_ext_obj = (ecma_extended_object_t *) object_p; + + if (!ecma_object_class_is (object_p, LIT_MAGIC_STRING_WEAKREF_UL)) + { + return ecma_raise_type_error ("Target is not weakRef"); + } + + return ecma_copy_value (this_ext_obj->u.class_prop.u.target); +} /* ecma_builtin_weakref_prototype_object_deref */ + +/** + * @} + * @} + * @} + */ + +#endif /* JERRY_BUILTIN_WEAKREF */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakref-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-weakref-prototype.inc.h new file mode 100644 index 000000000..0dccf506b --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakref-prototype.inc.h @@ -0,0 +1,41 @@ +/* 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 JERRY_BUILTIN_WEAKREF + +/* Object properties: + * (property name, object pointer getter) */ + +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_WEAKREF, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) + +STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_WEAKREF_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_DEREF, ecma_builtin_weakref_prototype_object_deref, 0, 0) + +#endif /* JERRY_BUILTIN_WEAKREF */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakref.c b/jerry-core/ecma/builtin-objects/ecma-builtin-weakref.c new file mode 100644 index 000000000..d339d7d76 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakref.c @@ -0,0 +1,97 @@ +/* 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 "jcontext.h" +#include "ecma-function-object.h" +#include "ecma-gc.h" + +#if JERRY_BUILTIN_WEAKREF + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-weakref.inc.h" +#define BUILTIN_UNDERSCORED_ID weakref +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup weakref ECMA WeakRef object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in WeakRef object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_weakref_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + uint32_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 WeakRef requires 'new'.")); +} /* ecma_builtin_weakref_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in WeakRef object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_weakref_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + uint32_t arguments_list_len) /**< number of arguments */ +{ + if (arguments_list_len == 0 || !ecma_is_value_object (arguments_list_p[0])) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("WeakRef target must be an object")); + } + + JERRY_ASSERT (JERRY_CONTEXT (current_new_target_p) != NULL); + + ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target_p), + ECMA_BUILTIN_ID_WEAKREF_PROTOTYPE); + + if (JERRY_UNLIKELY (proto_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ecma_object_t *object_p = ecma_create_object (proto_p, + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_CLASS); + ecma_deref_object (proto_p); + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; + ext_obj_p->u.class_prop.class_id = (uint16_t) LIT_MAGIC_STRING_WEAKREF_UL; + ext_obj_p->u.class_prop.u.target = arguments_list_p[0]; + ecma_op_object_set_weak (ecma_get_object_from_value (arguments_list_p[0]), object_p); + + return ecma_make_object_value (object_p); +} /* ecma_builtin_weakref_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* JERRY_BUILTIN_WEAKREF */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-weakref.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-weakref.inc.h new file mode 100644 index 000000000..6a2109ba4 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-weakref.inc.h @@ -0,0 +1,44 @@ +/* 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. + */ + +/* + * WeakRef built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if JERRY_BUILTIN_WEAKREF + +/* Number properties: + * (property name, number value, writable, enumerable, configurable) */ + +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 1, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +STRING_VALUE (LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_WEAKREF_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Object properties: + * (property name, object pointer getter) */ + +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_WEAKREF_PROTOTYPE, + ECMA_PROPERTY_FIXED) + +#endif /* JERRY_BUILTIN_WEAKREF */ + +#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 105459e91..cc73d1dbc 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -565,7 +565,25 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_WEAKSET, #endif /* JERRY_BUILTIN_WEAKSET */ -#if JERRY_BUILTIN_PROXY +#if JERRY_BUILTIN_WEAKREF + +/* The WeakRef prototype object */ +BUILTIN (ECMA_BUILTIN_ID_WEAKREF_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + weakref_prototype) + +/* The WeakRef routine */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_WEAKREF, + ECMA_OBJECT_TYPE_NATIVE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + weakref) + +#endif /* JERRY_BUILTIN_WEAKREF */ + +#if (JERRY_BUILTIN_PROXY) /* The Proxy routine (ECMA-262 v6, 26.2.1) */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_PROXY, ECMA_OBJECT_TYPE_NATIVE_FUNCTION, diff --git a/jerry-core/ecma/operations/ecma-container-object.c b/jerry-core/ecma/operations/ecma-container-object.c index 30613fe49..b3cb854d9 100644 --- a/jerry-core/ecma/operations/ecma-container-object.c +++ b/jerry-core/ecma/operations/ecma-container-object.c @@ -207,7 +207,7 @@ ecma_op_container_free_weakset_entries (ecma_object_t *object_p, /**< object poi continue; } - ecma_op_container_unref_weak (ecma_get_object_from_value (*entry_p), ecma_make_object_value (object_p)); + ecma_op_object_unref_weak (ecma_get_object_from_value (*entry_p), ecma_make_object_value (object_p)); ecma_op_container_remove_weak_entry (object_p, *entry_p); *entry_p = ECMA_VALUE_EMPTY; @@ -238,7 +238,7 @@ ecma_op_container_free_weakmap_entries (ecma_object_t *object_p, /**< object poi continue; } - ecma_op_container_unref_weak (ecma_get_object_from_value (entry_p->key), ecma_make_object_value (object_p)); + ecma_op_object_unref_weak (ecma_get_object_from_value (entry_p->key), ecma_make_object_value (object_p)); ecma_op_container_remove_weak_entry (object_p, entry_p->key); ecma_free_value_if_not_object (entry_p->value); @@ -666,48 +666,6 @@ ecma_op_container_has (ecma_extended_object_t *map_object_p, /**< map object */ return ecma_make_boolean_value (entry_p != NULL); } /* ecma_op_container_has */ -/** - * Set a weak reference from a container to a key object - */ -static void -ecma_op_container_set_weak (ecma_object_t *const key_p, /**< key object */ - ecma_extended_object_t *const container_p) /**< container */ -{ - if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (key_p))) - { - ecma_fast_array_convert_to_normal (key_p); - } - - ecma_string_t *weak_refs_string_p = ecma_get_internal_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS); - ecma_property_t *property_p = ecma_find_named_property (key_p, weak_refs_string_p); - ecma_collection_t *refs_p; - - if (property_p == NULL) - { - ecma_property_value_t *value_p; - ECMA_CREATE_INTERNAL_PROPERTY (key_p, weak_refs_string_p, property_p, value_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)); - } - - const ecma_value_t container_value = ecma_make_object_value ((ecma_object_t *) 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; - } - } - - ecma_collection_push_back (refs_p, container_value); -} /* ecma_op_container_set_weak */ - /** * Helper method for the Map.prototype.set and Set.prototype.add methods to swap the sign of the given value if needed * @@ -769,7 +727,7 @@ ecma_op_container_set (ecma_extended_object_t *map_object_p, /**< map object */ if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0) { ecma_object_t *key_p = ecma_get_object_from_value (key_arg); - ecma_op_container_set_weak (key_p, map_object_p); + ecma_op_object_set_weak (key_p, (ecma_object_t *) map_object_p); } #endif /* JERRY_BUILTIN_WEAKMAP || JERRY_BUILTIN_WEAKSET */ } @@ -906,38 +864,11 @@ ecma_op_container_delete_weak (ecma_extended_object_t *map_object_p, /**< map ob ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id); 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 ((ecma_object_t *) map_object_p)); + ecma_op_object_unref_weak (key_object_p, ecma_make_object_value ((ecma_object_t *) map_object_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_internal_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 */ diff --git a/jerry-core/ecma/operations/ecma-container-object.h b/jerry-core/ecma/operations/ecma-container-object.h index 2d2661911..c5d2bf94b 100644 --- a/jerry-core/ecma/operations/ecma-container-object.h +++ b/jerry-core/ecma/operations/ecma-container-object.h @@ -67,7 +67,6 @@ ecma_value_t ecma_op_container_delete (ecma_extended_object_t *map_object_p, ecm lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_delete_weak (ecma_extended_object_t *map_object_p, 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); void ecma_op_container_free_entries (ecma_object_t *object_p); ecma_value_t ecma_op_container_create_iterator (ecma_value_t this_arg, diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index c8547ac99..647382ef8 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -2650,6 +2650,9 @@ ecma_object_check_class_name_is_object (ecma_object_t *obj_p) /**< object */ #if JERRY_BUILTIN_WEAKMAP || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_WEAKMAP_PROTOTYPE) #endif /* JERRY_BUILTIN_WEAKMAP */ +#if JERRY_BUILTIN_WEAKREF + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_WEAKREF_PROTOTYPE) +#endif /* JERRY_BUILTIN_WEAKREF */ #if JERRY_BUILTIN_WEAKSET || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_WEAKSET_PROTOTYPE) #endif /* JERRY_BUILTIN_WEAKSET */ @@ -3239,6 +3242,82 @@ ecma_op_ordinary_object_has_own_property (ecma_object_t *object_p, /**< the obje return property != ECMA_PROPERTY_TYPE_NOT_FOUND && property != ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP; } /* ecma_op_ordinary_object_has_own_property */ +#if JERRY_BUILTIN_WEAKREF || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKMAP + +/** + * Set a weak reference from a container or WeakRefObject to a key object + */ +void +ecma_op_object_set_weak (ecma_object_t *object_p, /**< key object */ + ecma_object_t *target_p) /**< target object */ +{ + if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (object_p))) + { + ecma_fast_array_convert_to_normal (object_p); + } + + ecma_string_t *weak_refs_string_p = ecma_get_internal_string (LIT_INTERNAL_MAGIC_STRING_WEAK_REFS); + ecma_property_t *property_p = ecma_find_named_property (object_p, weak_refs_string_p); + ecma_collection_t *refs_p; + + if (property_p == NULL) + { + ecma_property_value_t *value_p; + ECMA_CREATE_INTERNAL_PROPERTY (object_p, weak_refs_string_p, property_p, value_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)); + } + + const ecma_value_t target_value = ecma_make_object_value ((ecma_object_t *) target_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] = target_value; + return; + } + } + + ecma_collection_push_back (refs_p, target_value); +} /* ecma_op_object_set_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_object_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_internal_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); + ecma_value_t *buffer_p = refs_p->buffer_p; + + while (true) + { + if (*buffer_p == ref_holder) + { + *buffer_p = ECMA_VALUE_EMPTY; + return; + } + JERRY_ASSERT (buffer_p < refs_p->buffer_p + refs_p->item_count); + buffer_p++; + } +} /* ecma_op_object_unref_weak */ + +#endif /* JERRY_BUILTIN_WEAKREF || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKMAP */ /** * Raise property redefinition error * diff --git a/jerry-core/ecma/operations/ecma-objects.h b/jerry-core/ecma/operations/ecma-objects.h index 1e84c2579..fad48f88d 100644 --- a/jerry-core/ecma/operations/ecma-objects.h +++ b/jerry-core/ecma/operations/ecma-objects.h @@ -109,6 +109,10 @@ ecma_value_t ecma_op_species_constructor (ecma_object_t *this_value, ecma_builti ecma_value_t ecma_op_invoke_by_symbol_id (ecma_value_t object, lit_magic_string_id_t magic_string_id, ecma_value_t *args_p, uint32_t args_len); #endif /* JERRY_ESNEXT */ +#if JERRY_BUILTIN_WEAKREF || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKMAP +void ecma_op_object_set_weak (ecma_object_t *object_p, ecma_object_t *target_p); +void ecma_op_object_unref_weak (ecma_object_t *object_p, ecma_value_t ref_holder); +#endif /* JERRY_BUILTIN_WEAKREF || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKMAP */ ecma_value_t ecma_op_invoke (ecma_value_t object, ecma_string_t *property_name_p, ecma_value_t *args_p, uint32_t args_len); ecma_value_t ecma_op_invoke_by_magic_id (ecma_value_t object, lit_magic_string_id_t magic_string_id, diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 0e0f97d70..58fddcbe5 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -109,6 +109,7 @@ typedef enum JERRY_FEATURE_GLOBAL_THIS, /**< GlobalThisValue support */ JERRY_FEATURE_PROMISE_CALLBACK, /**< Promise callback support */ JERRY_FEATURE_MODULE, /**< Module support */ + JERRY_FEATURE_WEAKREF, /**< WeakRef support */ JERRY_FEATURE__COUNT /**< number of features. NOTE: must be at the end of the list */ } jerry_feature_t; @@ -491,6 +492,7 @@ typedef enum JERRY_OBJECT_TYPE_SYMBOL, /**< Symbol object */ JERRY_OBJECT_TYPE_GENERATOR, /**< Generator object */ JERRY_OBJECT_TYPE_BIGINT, /**< BigInt object */ + JERRY_OBJECT_TYPE_WEAKREF, /**< WeakRef object */ } jerry_object_type_t; /** diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h index 6b6743d6b..49e249c87 100644 --- a/jerry-core/lit/lit-magic-strings.h +++ b/jerry-core/lit/lit-magic-strings.h @@ -67,6 +67,7 @@ typedef enum * data properties */ LIT_INTERNAL_MAGIC_STRING_ENVIRONMENT_RECORD, /**< dynamic environment record needed by class constructors */ LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED, /**< computed class field name list */ + LIT_INTERNAL_MAGIC_STRING_CONTAINER_WEAK_REFS, /**< Weak references to the current container object */ LIT_INTERNAL_MAGIC_STRING_WEAK_REFS, /**< Weak references to the current object */ 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 3ec2161ff..bc0c104cf 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -248,6 +248,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CLEAR, "clear") #if JERRY_BUILTIN_MATH && JERRY_ESNEXT LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CLZ32, "clz32") #endif +#if JERRY_BUILTIN_WEAKREF +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DEREF, "deref") +#endif #if JERRY_BUILTIN_ARRAY \ || JERRY_BUILTIN_TYPEDARRAY LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EVERY, "every") @@ -457,6 +460,10 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SYMBOL_DOT_UL, "Symbol.") || JERRY_BUILTIN_WEAKMAP LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKMAP_UL, "WeakMap") #endif +#if JERRY_BUILTIN_WEAKMAP || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKREF \ +|| JERRY_BUILTIN_WEAKREF +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKREF_UL, "WeakRef") +#endif #if JERRY_BUILTIN_CONTAINER \ || JERRY_BUILTIN_WEAKSET LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_WEAKSET_UL, "WeakSet") diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index 08dc19d44..07ff43092 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -111,6 +111,7 @@ LIT_MAGIC_STRING_ATANH = "atanh" LIT_MAGIC_STRING_CATCH = "catch" LIT_MAGIC_STRING_CLEAR = "clear" LIT_MAGIC_STRING_CLZ32 = "clz32" +LIT_MAGIC_STRING_DEREF = "deref" LIT_MAGIC_STRING_EVERY = "every" LIT_MAGIC_STRING_EXPM1 = "expm1" LIT_MAGIC_STRING_FALSE = "false" @@ -215,6 +216,7 @@ LIT_MAGIC_STRING_UNICODE = "unicode" LIT_MAGIC_STRING_UNSHIFT = "unshift" LIT_MAGIC_STRING_VALUE_OF_UL = "valueOf" LIT_MAGIC_STRING_WEAKMAP_UL = "WeakMap" +LIT_MAGIC_STRING_WEAKREF_UL = "WeakRef" LIT_MAGIC_STRING_WEAKSET_UL = "WeakSet" LIT_MAGIC_STRING_EPSILON_U = "EPSILON" LIT_MAGIC_STRING_DATAVIEW_UL = "DataView" diff --git a/jerry-core/profiles/README.md b/jerry-core/profiles/README.md index 7a1e62923..e907b4bcc 100644 --- a/jerry-core/profiles/README.md +++ b/jerry-core/profiles/README.md @@ -122,6 +122,8 @@ defined to `1`. Enables or disables the [WeakMap](https://262.ecma-international.org/11.0/#sec-weakmap-objects) built-in. * `JERRY_BUILTIN_WEAKSET`: Enables or disables the [WeakSet](https://262.ecma-international.org/11.0/#sec-weakmap-objects) built-in. +* `JERRY_BUILTIN_WEAKREF`: + Enables or disables the [WeakRef](https://tc39.es/ecma262/#sec-weak-ref-constructor) built-in. * `JERRY_MODULE_SYSTEM`: Enables or disable the [module system](http://www.ecma-international.org/ecma-262/6.0/#sec-modules) language element. * `JERRY_ESNEXT`: Enables or disables all of the implemented [ECMAScript2015+ features](http://www.ecma-international.org/ecma-262/10.0/) above. diff --git a/tests/jerry/es.next/weakref.js b/tests/jerry/es.next/weakref.js new file mode 100644 index 000000000..a6fff9184 --- /dev/null +++ b/tests/jerry/es.next/weakref.js @@ -0,0 +1,69 @@ +// 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 target_obj = {}; +var not_target_obj = {}; +var weak_ref = new WeakRef(target_obj); +var weak_ref2 = new WeakRef(target_obj); + +assert (weak_ref.deref() === target_obj); +assert (weak_ref.deref() === weak_ref2.deref()); +assert (weak_ref.deref() !== not_target_obj); + +assert (weak_ref2.deref() === target_obj); +assert (weak_ref2.deref() !== not_target_obj); +assert (weak_ref2.deref() === weak_ref2.deref()); + +target_obj = undefined; +gc(); + +assert (weak_ref.deref() === undefined); +assert (weak_ref2.deref() === undefined); + +var key_obj_1 = {}; +var key_obj_2 = {}; +var key_obj_3 = {}; +var target_obj_2 = {}; +var target_obj_3 = {}; +var weak_ref_3 = new WeakRef(key_obj_1); +var weak_ref_4 = new WeakRef(target_obj_2); +var weak_ref_5 = new WeakRef(target_obj_3); + +var weak_map = new WeakMap(); +weak_map.set(key_obj_1, weak_ref_3); +weak_map.set(key_obj_2, weak_ref_4); +weak_map.set(key_obj_3, weak_ref_5); + +assert(weak_map.has(key_obj_1)); +assert(weak_map.has(key_obj_2)); +assert(weak_map.has(key_obj_3)); + +assert(weak_map.get(key_obj_1).deref() === key_obj_1); +assert(weak_map.get(key_obj_2).deref() === target_obj_2); +assert(weak_map.get(key_obj_3).deref() === target_obj_3); + +key_obj_1 = undefined; +gc(); +assert(weak_map.get(key_obj_1) === undefined); +assert(weak_ref_3.deref() === undefined); + +key_obj_2 = undefined; +gc(); +assert(weak_map.get(key_obj_2) === undefined); +assert(weak_ref_4.deref() === target_obj_2); + +target_obj_3 = undefined; +gc(); +assert(weak_map.get(key_obj_3) !== undefined); +assert(weak_ref_5.deref() === undefined); diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index bd76163cf..76a8be35d 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -5295,32 +5295,8 @@ - - - - - - - - - - - - - - - - - - - - - - - -