diff --git a/spec.html b/spec.html index b4fd7d6987c..546bd2ca631 100644 --- a/spec.html +++ b/spec.html @@ -7765,6 +7765,11 @@

Agents

A candidate execution Record See the memory model. + + [[KeptAlive]] + List of objects + Initially a new empty List, representing the list of objects to be kept alive until the end of the current Job + @@ -7875,6 +7880,245 @@

Forward Progress

This, along with the liveness guarantee in the memory model, ensures that all ~SeqCst~ writes eventually become observable to all agents.

+ + +

Processing model of WeakRef and FinalizationRegistry objects

+ +

Objectives

+ +

+ This specification does not make any guarantees that any object will be garbage collected. + Objects which are unreachable from ECMAScript may be released after long periods + of time, or never at all. For this reason, this specification uses the term + "may" when describing behaviour triggered by garbage collection. +

+ +

+ The semantics of WeakRef and FinalizationRegistry objects is based on two + operations which happen at particular points in time: +

+ + + +

+ Neither of these actions (ClearKeptObjects or CleanupFinalizationRegistry) + may interrupt synchronous ECMAScript execution. Because embedding + environments may assemble longer, synchronous ECMAScript execution runs, + this specification defers the scheduling of ClearKeptObjects and + CleanupFinalizationRegistry to the embedding environment. +

+ +

+ Some ECMAScript implementations include garbage collector implementations + which run in the background, including when ECMAScript is idle. Letting the + embedding environment schedule CleanupFinalizationRegistry allows it to resume + ECMAScript execution in order to run finalizer work, which may free up held values, + reducing overall memory usage. +

+
+ + +

Liveness

+ +

+ For some set of objects _S_, a hypothetical WeakRef-oblivious + execution with respect to _S_ is an execution whereby + WeakRef.prototype.deref being called on a WeakRef whose referent is an + element of _S_ always returns *undefined*. +

+ + WeakRef-obliviousness, together with liveness, capture two notions. One, + that a WeakRef itself does not keep an object alive. Two, that cycles in + liveness does not imply that an object is live. To be concrete, if + determining _obj_'s liveness depends on determining the liveness of + another WeakRef referent, _obj2_, _obj2_'s liveness cannot assume + _obj_'s liveness, which would beg the question. + + + WeakRef-obliviousness is defined on sets of objects instead of + individual objects to account for cycles. If it were defined on + individual objects, then an object in a cycle will be considered live + even though its Object value is only observed via WeakRefs of other + objects in the cycle. + + +

+ At any point during evaluation, a set of objects _S_ is + considered live if either of the following conditions is + met: +

+ + + + The intuition the second condition above intends to capture is that an + object is live if its identity is observable via non-WeakRef means. An + object's identity may be observed by observing a strict equality + comparison between objects or observing the object being used as key in + a Map. + + + Presence of an object in a field, an internal slot, or a property does + not imply that the object is live. For example if the object in + question is never passed back to the program, then it cannot be + observed. + + This is the case for keys in a WeakMap, members of a WeakSet, as well + as the [[WeakRefTarget]] and [[UnregisterToken]] fields of a FinalizationRegistry + Cell record. + + The above definition implies that, if a key in a WeakMap is not live, + then its corresponding value is not necessarily live either. + + + Liveness is the lower bound for guaranteeing which WeakRefs that + engines must not empty. In practice, liveness as defined here is + undecidable and engines use conservative approximations. There is + expected to be significant implementation leeway. + +
+ + +

Execution

+ +

At any time, if a set of objects _S_ is not live, an ECMAScript implementation may perform the following steps atomically:

+ + + 1. For each _obj_ of _S_, do + 1. For each WeakRef _ref_ such that _ref_.[[WeakRefTarget]] is _obj_, do + 1. Set _ref_.[[WeakRefTarget]] to ~empty~. + 1. For each FinalizationRegistry _fg_ such that _fg_.[[Cells]] contains _cell_, such that _cell_.[[WeakRefTarget]] is _obj_, do + 1. Set _cell_.[[WeakRefTarget]] to ~empty~. + 1. Optionally, perform ! HostCleanupFinalizationRegistry(_fg_). + 1. For each WeakMap _map_ such that _map_.[[WeakMapData]] contains a record _r_ such that _r_.[[Key]] is _obj_, do + 1. Remove _r_ from _map_.[[WeakMapData]]. + 1. For each WeakSet _set_ such that _set_.[[WeakSetData]] contains _obj_, do + 1. Remove _obj_ from _set_.[[WeakSetData]]. + + + +

+ Together with the definition of liveness, this clause prescribes legal + optimizations that an implementation may apply regarding WeakRefs. +

+ +

+ It is possible to access an object without observing its + identity. Optimizations such as dead variable elimination, and scalar + replacement on properties of non-escaping objects whose identity is not + observed, are allowed. These optimizations are thus allowed to + observably empty WeakRefs that point to such objects. +

+ +

+ On the other hand, if an object's identity is observable, and that + object is in the [[WeakRefTarget]] internal slot of a WeakRef, optimizations + such as rematerialization that observably empty the WeakRef are + prohibited. +

+ +

+ Because calling HostCleanupFinalizationRegistry is optional, registered objects + in a FinalizationRegistry do not necessarily hold that FinalizationRegistry live. + Implementations may omit FinalizationRegistry callbacks for any reason, + e.g., if the FinalizationRegistry itself becomes dead, or if the application + is shutting down. +

+
+ +

+ Implementations are not obligated to empty WeakRefs for maximal sets + of non-live objects. +

+

+ If an implementation chooses a non-live set _S_ in which to empty WeakRefs, it + must empty WeakRefs for all objects in _S_ simultaneously. In other + words, an implementation must not empty a WeakRef pointing to an object _obj_ + without emptying out other WeakRefs that, if not emptied, could result + in an execution that observes the Object value of _obj_. +

+
+
+ + +

Host Hooks

+ + +

HostCleanupFinalizationRegistry ( _finalizationRegistry_ )

+ +

+ HostCleanupFinalizationRegistry is an implementation-defined abstract + operation that is expected to call CleanupFinalizationRegistry(_finalizationRegistry_) at + some point in the future, if possible. The host's responsibility is to + make this call at a time which does not interrupt synchronous + ECMAScript code execution. +

+
+
+
+ + +

ClearKeptObjects ( )

+

+ ECMAScript implementations are expected to call ClearKeptObjects when a + synchronous sequence of ECMAScript execution completes. +

+

The following steps are performed:

+ + 1. Let _agent_ be the surrounding agent. + 1. Set _agent_.[[KeptAlive]] to a new empty List. + +
+ + +

AddToKeptObjects ( _object_ )

+ + 1. Let _agent_ be the surrounding agent. + 1. Append _object_ to _agent_.[[KeptAlive]]. + + + When the abstract operation AddToKeptObjects is called with a + target object reference, it adds the target to an identity Set + that will point strongly at the target until ClearKeptObjects is + called. + +
+ + +

CleanupFinalizationRegistry ( _finalizationRegistry_ [ , _callback_ ] )

+

The following steps are performed:

+ + 1. Assert: _finalizationRegistry_ has [[Cells]] and [[CleanupCallback]] internal slots. + 1. If _callback_ is not present or *undefined*, set _callback_ to _finalizationRegistry_.[[CleanupCallback]]. + 1. While _finalizationRegistry_.[[Cells]] contains a Record _cell_ such that _cell_.[[WeakRefTarget]] is ~empty~, then an implementation may perform the following steps: + 1. Choose any such _cell_. + 1. Remove _cell_ from _finalizationRegistry_.[[Cells]]. + 1. Perform ? Call(_callback_, *undefined*, « _cell_.[[HeldValue]] »). + 1. Return NormalCompletion(*undefined*). + +
@@ -36583,7 +36827,7 @@

Properties of Set Iterator Instances

WeakMap Objects

-

WeakMap objects are collections of key/value pairs where the keys are objects and values may be arbitrary ECMAScript language values. A WeakMap may be queried to see if it contains a key/value pair with a specific key, but no mechanism is provided for enumerating the objects it holds as keys. If an object that is being used as the key of a WeakMap key/value pair is only reachable by following a chain of references that start within that WeakMap, then that key/value pair is inaccessible and is automatically removed from the WeakMap. WeakMap implementations must detect and remove such key/value pairs and any associated resources.

+

WeakMap objects are collections of key/value pairs where the keys are objects and values may be arbitrary ECMAScript language values. A WeakMap may be queried to see if it contains a key/value pair with a specific key, but no mechanism is provided for enumerating the objects it holds as keys. In certain conditions, objects which are not live are removed as WeakMap keys, as described in .

An implementation may impose an arbitrarily determined latency between the time a key/value pair of a WeakMap becomes inaccessible and the time when the key/value pair is removed from the WeakMap. If this latency was observable to ECMAScript program, it would be a source of indeterminacy that could impact program execution. For that reason, an ECMAScript implementation must not provide any means to observe a key of a WeakMap that does not require the observer to present the observed key.

WeakMap objects must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of key/value pairs in the collection. The data structure used in this WeakMap objects specification are only intended to describe the required observable semantics of WeakMap objects. It is not intended to be a viable implementation model.

@@ -36731,7 +36975,7 @@

Properties of WeakMap Instances

WeakSet Objects

-

WeakSet objects are collections of objects. A distinct object may only occur once as an element of a WeakSet's collection. A WeakSet may be queried to see if it contains a specific object, but no mechanism is provided for enumerating the objects it holds. If an object that is contained by a WeakSet is only reachable by following a chain of references that start within that WeakSet, then that object is inaccessible and is automatically removed from the WeakSet. WeakSet implementations must detect and remove such objects and any associated resources.

+

WeakSet objects are collections of objects. A distinct object may only occur once as an element of a WeakSet's collection. A WeakSet may be queried to see if it contains a specific object, but no mechanism is provided for enumerating the objects it holds. In certain conditions, objects which are not live are removed as WeakSet elements, as described in .

An implementation may impose an arbitrarily determined latency between the time an object contained in a WeakSet becomes inaccessible and the time when the object is removed from the WeakSet. If this latency was observable to ECMAScript program, it would be a source of indeterminacy that could impact program execution. For that reason, an ECMAScript implementation must not provide any means to determine if a WeakSet contains a particular object that does not require the observer to present the observed object.

WeakSet objects must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements in the collection. The data structure used in this WeakSet objects specification is only intended to describe the required observable semantics of WeakSet objects. It is not intended to be a viable implementation model.

@@ -38592,6 +38836,326 @@

JSON [ @@toStringTag ]

+ +

Managing Memory

+ + +

WeakRef Objects

+

+ A WeakRef is an object that is used to refer to a target object + without preserving it from garbage collection. WeakRefs can + dereference to allow access to the target object, if the target + object hasn't been reclaimed by garbage collection. +

+ + +

The WeakRef Constructor

+

The WeakRef constructor:

+
    +
  • is the intrinsic object %WeakRef%.
  • +
  • + is the initial value of the `WeakRef` property of the global + object. +
  • +
  • + creates and initializes a new WeakRef object when called as a + constructor. +
  • +
  • + is not intended to be called as a function and will throw an + exception when called in that manner. +
  • +
  • + is designed to be subclassable. It may be used as the value + in an `extends` clause of a class definition. Subclass + constructors that intend to inherit the specified `WeakRef` + behaviour must include a `super` call to the `WeakRef` constructor + to create and initialize the subclass instance with the internal + state necessary to support the `WeakRef.prototype` built-in + methods. +
  • +
+ + +

WeakRef ( _target_ )

+

+ When the `WeakRef` function is called with argument _target_, + the following steps are taken: +

+ + 1. If NewTarget is *undefined*, throw a *TypeError* exception. + 1. If Type(_target_) is not Object, throw a *TypeError* exception. + 1. Let _weakRef_ be ? OrdinaryCreateFromConstructor(NewTarget, + `"%WeakRef.prototype%"`, « [[WeakRefTarget]] »). + 1. Perfom ! AddToKeptObjects(_target_). + 1. Set _weakRef_.[[WeakRefTarget]] to _target_. + 1. Return _weakRef_. + +
+
+ + +

Properties of the WeakRef Constructor

+

The WeakRef constructor:

+
    +
  • + has a [[Prototype]] internal slot whose value is the intrinsic + object %Function.prototype%. +
  • +
  • has the following properties:
  • +
+ + +

WeakRef.prototype

+

+ The initial value of `WeakRef.prototype` is the intrinsic + %WeakRef.prototype% object. +

+

+ This property has the attributes { [[Writable]]: *false*, + [[Enumerable]]: *false*, [[Configurable]]: *false* }. +

+
+
+ + +

Properties of the WeakRef Prototype Object

+

The WeakRef prototype object:

+
    +
  • is the intrinsic object %WeakRef.prototype%.
  • +
  • + has a [[Prototype]] internal slot whose value is the intrinsic + object %Object.prototype%. +
  • +
  • is an ordinary object.
  • +
  • does not have a [[WeakRefTarget]] internal slot.
  • +
+ + +

WeakRef.prototype.constructor

+ +

The initial value of `WeakRef.prototype.constructor` is the intrinsic object %WeakRef%.

+ +

This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.

+
+ + +

WeakRef.prototype.deref ( )

+

The following steps are taken:

+ + 1. Let _weakRef_ be the *this* value. + 1. Perform ? RequireInternalSlot(_weakRef_, [[WeakRefTarget]]). + 1. Let _target_ be the value of _weakRef_.[[WeakRefTarget]]. + 1. If _target_ is not ~empty~, then + 1. Perform ! AddToKeptObjects(_target_). + 1. Return _target_. + 1. Return *undefined*. + + + + If the WeakRef returns a _target_ Object that is not + *undefined*, then this _target_ object should not be garbage + collected in that turn. The AddToKeptObjects operation makes sure + read consistency is maintained. + +
+            target = { foo: function() {} };
+            let weakRef = new WeakRef(target);
+
+            ... later ...
+
+            if (weakRef.deref()) {
+              weakRef.deref().foo();
+            }
+          
+ + In the above example, if the first deref evaluates to true + then the second deref can not fail. +
+
+ + +

WeakRef.prototype [ @@toStringTag ]

+

The initial value of the @@toStringTag property is the String value `"WeakRef"`.

+

This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.

+
+
+ + +

Properties of WeakRef Instances

+

+ WeakRef instances are ordinary objects that inherit properties from + the WeakRef prototype. WeakRef instances also have a [[WeakRefTarget]] + internal slot. +

+
+
+ + +

FinalizationRegistry Objects

+

+ A FinalizationRegistry is an object that manages registration and + unregistration of cleanup operations that are performed when + target objects are garbage collected. +

+ + +

The FinalizationRegistry Constructor

+

The FinalizationRegistry constructor:

+
    +
  • is the intrinsic object %FinalizationRegistry%.
  • +
  • + is the initial value of the `FinalizationRegistry` property of + the global object. +
  • +
  • + creates and initializes a new FinalizationRegistry object when + called as a constructor. +
  • +
  • + is not intended to be called as a function and will throw an + exception when called in that manner. +
  • +
  • + is designed to be subclassable. It may be used as the value in + an `extends` clause of a class definition. Subclass + constructors that intend to inherit the specified + `FinalizationRegistry` behaviour must include a `super` call to + the `FinalizationRegistry` constructor to create and initialize + the subclass instance with the internal state necessary to + support the `FinalizationRegistry.prototype` built-in methods. +
  • +
+ + +

FinalizationRegistry ( _cleanupCallback_ )

+

+ When the `FinalizationRegistry` function is called with argument _cleanupCallback_, + the following steps are taken: +

+ + 1. If NewTarget is *undefined*, throw a *TypeError* exception. + 1. If IsCallable(_cleanupCallback_) is *false*, throw a *TypeError* exception. + 1. Let _finalizationRegistry_ be ? OrdinaryCreateFromConstructor(NewTarget, + `"%FinalizationRegistry.prototype%"`, « [[Realm]], [[CleanupCallback]], + [[Cells]] »). + 1. Let _fn_ be the active function object. + 1. Set _finalizationRegistry_.[[Realm]] to _fn_.[[Realm]]. + 1. Set _finalizationRegistry_.[[CleanupCallback]] to _cleanupCallback_. + 1. Set _finalizationRegistry_.[[Cells]] to be an empty List. + 1. Return _finalizationRegistry_. + +
+
+ + +

Properties of the FinalizationRegistry Constructor

+

The FinalizationRegistry constructor:

+
    +
  • + has a [[Prototype]] internal slot whose value is the intrinsic + object %Function.prototype%. +
  • +
  • has the following properties:
  • +
+ + +

FinalizationRegistry.prototype

+

+ The initial value of `FinalizationRegistry.prototype` is the + intrinsic %FinalizationRegistry.prototype% object. +

+

+ This property has the attributes { [[Writable]]: *false*, + [[Enumerable]]: *false*, [[Configurable]]: *false* }. +

+
+
+ + +

Properties of the FinalizationRegistry Prototype Object

+

The FinalizationRegistry prototype object:

+
    +
  • is the intrinsic object %FinalizationRegistry.prototype%.
  • +
  • + has a [[Prototype]] internal slot whose value is the intrinsic + object %Object.prototype%. +
  • +
  • is an ordinary object.
  • +
  • + does not have [[Cells]] and [[CleanupCallback]] internal slots. +
  • +
+ + +

FinalizationRegistry.prototype.constructor

+

The initial value of + `FinalizationRegistry.prototype.constructor` is the intrinsic + object %FinalizationRegistry%.

+
+ + +

FinalizationRegistry.prototype.register ( _target_, _heldValue_ [, _unregisterToken_ ] )

+

The following steps are taken:

+ + 1. Let _finalizationRegistry_ be the *this* value. + 1. Perform ? RequireInternalSlot(_finalizationRegistry_, [[Cells]]). + 1. If Type(_target_) is not Object, throw a *TypeError* exception. + 1. If SameValue(_target_, _heldValue_), throw a *TypeError* exception. + 1. If Type(_unregisterToken_) is not Object, then + 1. If _unregisterToken_ is not *undefined*, throw a *TypeError* exception. + 1. Set _unregisterToken_ to ~empty~. + 1. Let _cell_ be the Record { [[WeakRefTarget]] : _target_, [[HeldValue]]: _heldValue_, + [[UnregisterToken]]: _unregisterToken_ }. + 1. Append _cell_ to _finalizationRegistry_.[[Cells]]. + 1. Return *undefined*. + + + + Based on the algorithms and definitions in this specification, across the time when + _cell_ is in _finalizationRegistry_.[[Cells]], then _cell_.[[Holdings]] is live; + however, _cell_.[[UnregisterToken]] and _cell_.[[Target]] are not necessarily live. + For example, registering an object with itself as its unregister token would not + keep the object alive forever. + +
+ + +

FinalizationRegistry.prototype.unregister ( _unregisterToken_ )

+

The following steps are taken:

+ + 1. Let _finalizationRegistry_ be the *this* value. + 1. Perform ? RequireInternalSlot(_finalizationRegistry_, [[Cells]]). + 1. If Type(_unregisterToken_) is not Object, throw a *TypeError* exception. + 1. Let _removed_ be *false*. + 1. For each Record { [[WeakRefTarget]], [[HeldValue]], + [[UnregisterToken]] } _cell_ that is an element of + _finalizationRegistry_.[[Cells]], do + 1. If _cell_.[[UnregisterToken]] is not ~empty~ and + SameValue(_cell_.[[UnregisterToken]], _unregisterToken_) is *true*, then + 1. Remove _cell_ from _finalizationRegistry_.[[Cells]]. + 1. Set _removed_ to *true*. + 1. Return _removed_. + +
+ + +

FinalizationRegistry.prototype [ @@toStringTag ]

+

The initial value of the @@toStringTag property is the String value `"FinalizationRegistry"`.

+

This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.

+
+
+ + +

Properties of FinalizationRegistry Instances

+

+ FinalizationRegistry instances are ordinary objects that inherit + properties from the FinalizationRegistry prototype. FinalizationRegistry + instances also have [[Cells]] and [[CleanupCallback]] internal slots. +

+
+
+

Control Abstraction Objects