diff --git a/source b/source index 050f7ca8851..efcba355fe2 100644 --- a/source +++ b/source @@ -2770,6 +2770,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
  • delete an existing named property
  • perform a security check
  • platform object
  • +
  • primary interface
  • interface object
  • interface prototype object
  • global environment associated with a platform object
  • @@ -2900,8 +2901,9 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
  • The ArrayCreate abstract operation
  • The Call abstract operation
  • -
  • The CloneArrayBuffer abstract operation
  • The Construct abstract operation
  • +
  • The CopyDataBlockBytes abstract operation
  • +
  • The CreateByteDataBlock abstract operation
  • The CreateDataProperty abstract operation
  • The DetachArrayBuffer abstract operation
  • The EnqueueJob abstract operation
  • @@ -3180,11 +3182,13 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute spec=FILEAPI>

    @@ -7619,33 +7623,117 @@ interface DOMStringList {

    This section uses the terminology and typographic conventions from the JavaScript specification.

    -

    Cloneable objects

    +

    Serializable objects

    -

    Cloneable objects support being cloned across event - loops. That is, they support being cloned across document and worker boundaries, including - across documents of different origins. Not all objects are - cloneable objects and not all aspects of objects that are cloneable - objects are necessarily preserved when cloned.

    +

    Serializable objects support being serialized, and later deserialized, in a way + that is independent of any given JavaScript Realm. This allows them to be stored on + disk and later restored, or cloned across document and worker boundaries (including across + documents of different origins or in different event loops).

    -

    Platform objects have the following internal method:

    +

    Not all objects are serializable objects, and not all aspects of objects that are + serializable objects are necessarily preserved when they are serialized.

    -

    [[Clone]] ( targetRealm, memory )

    +

    Platform objects can be serializable objects + if they implement only interfaces decorated with the [Serializable] IDL extended attribute. Such + interfaces must also define the following algorithms:

    - +
    +
    serialization steps, taking a platform object + value and a Record serialized
    +
    +

    A set of steps that serializes the data in input into fields of + serialized. The resulting data serialized into serialized must be + independent of any JavaScript Realm.

    + +

    These steps may throw an exception if serialization is not possible.

    + +

    These steps may perform a sub-serialization to serialize nested data + structures. They should not call StructuredSerialize directly, as doing so will + omit the important memory argument.

    +
    + +
    deserialization steps, taking a Record + serialized and a platform object value
    +
    +

    A set of steps that deserializes the data in serialized, using it to set up + value as appropriate. value will be a newly-created instance of the + platform object type in question, with none of its internal data set up; setting + that up is the job of these steps.

    + +

    These steps may throw an exception if deserialization is not possible.

    + +

    These steps may perform a sub-deserialization to deserialize nested data + structures. They should not call StructuredDeserialize directly, as doing so will + omit the important targetRealm and memory arguments.

    +
    +
    + +

    It is up to the definition of individual platform objects to determine what data is serialized + and deserialized by these steps. Typically the steps are very symmetric.

    + +

    The [Serializable] extended attribute must take no + arguments, and must not appear on anything other than an interface. It must appear only once on an + interface. It must not be used on a callback interface. If it appears on a partial interface or an + interface that is really a mixin, then it must also appear on the original or mixed-in-to + interface, and any supplied serialization steps and deserialization + steps for the partial interface or mixin should be understood as being appended to those of + the original or mixed-in-to interface.

    + +
    +

    Let's say we were defining a platform object Person, which had + associated with it two pieces of associated data:

    -

    Unless specified otherwise, invoking the [[Clone]]() internal method must throw a - "DataCloneError" DOMException. (By default, platform objects are not cloneable objects.)

    + + +

    We could then define Person instances to be serializable + objects by annotating the Person interface with the [Serializable] extended attribute, and defining the + following accompanying algorithms:

    + +
    +
    serialization steps
    +
    +
      +
    1. Set serialized.[[Name]] to value's associated name + value.

    2. + +
    3. Let serializedBestFriend be the sub-serialization of + value's associated best friend value.

    4. + +
    5. Set serialized.[[BestFriend]] to serializedBestFriend.

    6. +
    +
    + +
    deserialization steps
    +
    +
      +
    1. Set value's associated name value to + serialized.[[Name]].

    2. + +
    3. Let deserializedBestFriend be the sub-deserialization of + serialized.[[BestFriend]].

    4. + +
    5. Set value's associated best friend value to + deserializedBestFriend.

    6. +
    +
    +
    +
    -

    Platform objects that are cloneable objects - have a [[Clone]]() internal method which is specified to run a series of steps. The - result of running those steps must be a thrown exception or a clone of this, created in - targetRealm. It is up such objects to define what cloning means for them.

    +

    Objects defined in the JavaScript specification are handled by the + StructuredSerialize abstract operation directly.

    -

    Objects defined in the JavaScript specification are handled by the StructuredClone - abstract operation directly.

    +

    Originally, this specification defined the concept of + "cloneable objects", which could be cloned from one JavaScript Realm to another. + However, to better specify the behavior of certain more complex situations, the model was updated + to make the serialization and deserialization explicit.

    Transferable objects

    @@ -7659,246 +7747,228 @@ interface DOMStringList {

    Transferring is an irreversible and non-idempotent operation. Once an object has been transferred, it cannot be transferred, or indeed used, again.

    -

    Platform objects that are transferable - objects have a [[Detached]] internal slot and the following internal method:

    - -

    [[Transfer]]( targetRealm )

    - +

    Platform objects can be transferable objects + if they implement only interfaces decorated with the [Transferable] IDL extended attribute. Such + interfaces must also define the following algorithms:

    -

    Whereas all platform objects have a - [[Clone]]() internal method, not all have a [[Detached]] internal slot - and a [[Transfer]]() internal method.

    - -

    Platform objects that are transferable - objects must define the [[Transfer]]() internal method such that it either - throws an exception or returns a clone of this, created in targetRealm, with - this's underlying data shared with the return value, and this's - [[Detached]] internal slot value set to true. It is up to such objects to define what - transferring means for them.

    +
    +
    transfer steps, taking a platform object + value and a Record dataHolder
    +
    +

    A set of steps that transfers the data in input into fields of + dataHolder. The resulting data held in dataHolder must be + independent of any JavaScript Realm.

    -

    Objects defined in the JavaScript specification are handled by the - StructuredCloneWithTransfer abstract operation directly. (Technically, by - IsTransferable and Transfer.)

    +

    These steps may throw an exception if transferral is not possible.

    +
    -

    StructuredCloneWithTransfer ( input, - transferList, targetRealm )

    +
    transfer-receiving steps, taking a Record + dataHolder and a platform object value
    +
    +

    A set of steps that receives the data in dataHolder, using it to set up + value as appropriate. value will be a newly-created instance of the + platform object type in question, with none of its internal data set up; setting + that up is the job of these steps.

    -
      -
    1. -

      Let memory be an empty map.

      +

      These steps may throw an exception if it is not possible to receive the transfer.

      +
    +
    -

    The purpose of the memory map, both here and in the - StructuredClone abstract operation, is to avoid cloning objects twice. This ends up - preserving cycles and the identity of duplicate objects in graphs.

    - +

    It is up to the definition of individual platform objects to determine what data is transferred + by these steps. Typically the steps are very symmetric.

    -
  • -

    For each object transferable in transferList: +

    The [Transferable] extended attribute must take no + arguments, and must not appear on anything other than an interface. It must appear only once on an + interface. It must not be used on a callback interface. If it appears on a partial interface or an + interface that is really a mixin, then it must also appear on the original or mixed-in-to + interface, and any supplied serialization steps and deserialization + steps for the partial interface or mixin should be understood as being appended to those of + the original or mixed-in-to interface.

    -
      -
    1. If IsTransferable(transferable) is false, then throw a - "DataCloneError" DOMException.

    2. +

      Platform objects that are transferable + objects have a [[Detached]] internal slot. This is used to ensure that once a + platform object has been transferred, it cannot be transferred again.

      -
    3. Let placeholder be a user-agent-defined placeholder object.

    4. +

      Objects defined in the JavaScript specification are handled by the + StructuredSerializeWithTransfer abstract operation directly.

      -
    5. Create an entry in memory with key transferable and value - placeholder.

    6. -
    -
  • +

    StructuredSerialize ( value [ , + memory ] )

    -
  • Let clone be the result of ? - StructuredClone(input, targetRealm, - memory).

  • +

    The StructuredSerialize abstract operation takes as input a JavaScript value + value and serializes it to a Realm-independent + form, represented here as a Record. This serialized form has all the information + necessary to later deserialize into a new JavaScript value in a different Realm.

    -
  • Let outputTransferList be a new empty List.

  • +

    This process may throw an exception, for example when trying to serialize un-serializable + objects.

    +
    1. -

      For each object transferable in transferList: +

      If memory was not supplied, let memory be an empty map.

      -
        -
      1. Let placeholderResult be the value of the entry in memory whose - key is transferable.

      2. - -
      3. Let transferResult be ? Transfer(transferable, - targetRealm).

      4. - -
      5. -

        Within clone, replace references to placeholderResult with - transferResult, such that everything holding a reference to - placeholderResult, now holds a reference to transferResult.

        - -

        This is a rather unusual low-level operation for which no primitives are - defined by JavaScript.

        -
      6. - -
      7. Add transferResult as the last element of - outputTransferList.

      8. -
      +

      The purpose of the memory map is to avoid serializing objects twice. + This ends up preserving cycles and the identity of duplicate objects in graphs.

    2. -
    3. Return { [[Clone]]: clone, [[TransferList]]: outputTransferList - }.

    4. -
    - -

    Originally the StructuredCloneWithTransfer abstract operation was - known as the "structured clone" algorithm. The StructuredClone abstract operation was - known as the "internal structured clone" algorithm. Transferring objects, now handled by the - StructuredCloneWithTransfer abstract operation, were formerly handled by parts of the - algorithm of the postMessage() method on the - Window object and the postMessage() - method on the MessagePort object.

    - - -

    StructuredClone ( input, targetRealm - [ , memory ] )

    +
  • If memory[value] exists, then + return memory[value].

  • -
      -
    1. If memory was not supplied, let memory be an empty map.

    2. - -
    3. If memory contains an entry with key input, then return that entry's - value.

    4. +
    5. Let deep be false.

    6. -
    7. If Type(input) is Undefined, Null, Boolean, - String, or Number, then return input.

    8. +
    9. If Type(value) is Undefined, Null, Boolean, + String, or Number, then return { [[Type]]: "primitive", [[Value]]: value }.

    10. -
    11. If Type(input) is Symbol, then throw a +

    12. If Type(value) is Symbol, then throw a "DataCloneError" DOMException.

    13. -
    14. Let deepClone be false.

    15. +
    16. Let serialized be an uninitialized value.

    17. -
    18. If input has a [[BooleanData]] internal slot, then let output be a - new Boolean object in targetRealm whose [[BooleanData]] internal slot value is the - [[BooleanData]] internal slot value of input.

    19. +
    20. If value has a [[BooleanData]] internal slot, then set serialized to + { [[Type]]: "Boolean", [[BooleanData]]: value.[[BooleanData]] }.

    21. -
    22. Otherwise, if input has a [[NumberData]] internal slot, then let - output be a new Number object in targetRealm whose [[NumberData]] internal - slot value is the [[NumberData]] internal slot value of input.

    23. +
    24. Otherwise, if value has a [[NumberData]] internal slot, then set + serialized to { [[Type]]: "Number", [[NumberData]]: value.[[NumberData]] + }.

    25. -
    26. Otherwise, if input has a [[StringData]] internal slot, then let - output be a new String object in targetRealm whose [[StringData]] internal - slot value is the [[StringData]] internal slot value of input.

    27. +
    28. Otherwise, if value has a [[StringData]] internal slot, then set + serialized to { [[Type]]: "String", [[StringData]]: value.[[StringData]] + }.

    29. -
    30. Otherwise, if input has a [[DateValue]] internal slot, then let - output be a new Date object in targetRealm whose [[DateValue]] internal - slot value is the [[DateValue]] internal slot value of input.

    31. +
    32. Otherwise, if value has a [[DateValue]] internal slot, then set + serialized to { [[Type]]: "Date", [[DateValue]]: value.[[DateValue]] + }.

    33. -
    34. Otherwise, if input has a [[RegExpMatcher]] internal slot, then let - output be a new RegExp object in targetRealm whose [[RegExpMatcher]] - internal slot value is the [[RegExpMatcher]] internal slot value of input, whose - [[OriginalSource]] internal slot value is the [[OriginalSource]] internal slot value of - input, and whose whose [[OriginalFlags]] internal slot value is the [[OriginalFlags]] - internal slot value of input.

    35. +
    36. Otherwise, if value has a [[RegExpMatcher]] internal slot, then set + serialized to { [[Type]]: "RegExp", [[RegExpMatcher]]: + value.[[RegExpMatcher]], [[OriginalSource]]: value.[[OriginalSource]], + [[OriginalFlags]]: value.[[OriginalFlags]] }.

    37. -

      Otherwise, if input has an [[ArrayBufferData]] internal slot, then:

      +

      Otherwise, if value has an [[ArrayBufferData]] internal slot, then:

        -
      1. If IsDetachedBuffer(input) is true, then throw a +

      2. If IsDetachedBuffer(value) is true, then throw a "DataCloneError" DOMException.

      3. -
      4. Let outputArrayBuffer be the %ArrayBuffer% intrinsic object in - targetRealm. +

      5. Let size be value.[[ArrayBufferByteLength]].

      6. + +
      7. +

        Let dataCopy be ? CreateByteDataBlock(size).

        + +

        This can throw a RangeError exception upon + allocation failure.

        +
      8. + +
      9. Perform ! CopyDataBlockBytes(dataCopy, 0, + value.[[ArrayBufferData]], 0, size).

      10. -
      11. Let output be ? CloneArrayBuffer(input, 0, - outputArrayBuffer).

      12. +
      13. Set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: + dataCopy, [[ArrayBufferByteLength]]: size }.

    38. -

      Otherwise, if input has a [[ViewedArrayBuffer]] internal slot, then:

      +

      Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:

        -
      1. Let buffer be the value of input's [[ViewedArrayBuffer]] internal +

      2. Let buffer be the value of value's [[ViewedArrayBuffer]] internal slot.

      3. -
      4. Let bufferClone be ? StructuredClone(buffer, - targetRealm, memory).

      5. +
      6. Let bufferSerialized be ? StructuredSerialize(buffer, + memory).

      7. -
      8. If input has a [[DataView]] internal slot, then let output be a - new DataView object in targetRealm whose [[DataView]] internal slot value is true, - whose [[ViewedArrayBuffer]] internal slot value is bufferClone, whose [[ByteLength]] - internal slot value is the [[ByteLength]] internal slot value of input, and whose - [[ByteOffset]] internal slot value is the [[ByteOffset]] internal slot value of - input.

      9. +
      10. Assert: bufferSerialized.[[Type]] is "ArrayBuffer".

      11. + +
      12. If value has a [[DataView]] internal slot, then set serialized to + { [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView", [[ArrayBufferSerialized]]: + bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: + value.[[ByteOffset]] }.

      13. Otherwise:

          -
        1. Assert: input has a [[TypedArrayName]] internal slot.

        2. - -
        3. Let constructor be the intrinsic object listed in column one of The - TypedArray Constructors table for the value of input's - [[TypedArrayName]] internal slot in targetRealm.

        4. - -
        5. Let byteOffset be input's [[ByteOffset]] internal slot - value.

        6. - -
        7. Let length be input's [[ArrayLength]] internal slot - value.

        8. +
        9. Assert: value has a [[TypedArrayName]] internal slot.

        10. -
        11. Let output be ? TypedArrayCreate(constructor, - « bufferClone, byteOffset, length »). +

        12. Set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: + value.[[TypedArrayName]], [[ArrayBufferSerialized]]: bufferSerialized, + [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: + value.[[ByteOffset]], [[ArrayLength]]: value.[[ArrayLength]] }.

    39. -

      Otherwise, if input has [[MapData]] internal slot, then:

      +

      Otherwise, if value has [[MapData]] internal slot, then:

        -
      1. Let output be a new Map object in targetRealm whose [[MapData]] - internal slot value is a new empty List.

      2. +
      3. Set serialized to { [[Type]]: "Map", [[MapData]]: a new empty List }.

      4. -
      5. Set deepClone to true.

      6. +
      7. Set deep to true.

    40. -

      Otherwise, if input has [[SetData]] internal slot, then:

      +

      Otherwise, if value has [[SetData]] internal slot, then:

        -
      1. Let output be a new Set object in targetRealm whose [[SetData]] - internal slot value is a new empty List.

      2. +
      3. Set serialized to { [[Type]]: "Set", [[SetData]]: a new empty List }.

      4. -
      5. Set deepClone to true.

      6. +
      7. Set deep to true.

    41. -

      Otherwise, if input is an Array exotic object, then:

      +

      Otherwise, if value is an Array exotic object, then:

        -
      1. Let inputLen be OrdinaryGetOwnProperty(input, - "length").[[Value]].

      2. +
      3. Let inputLenDescriptor be ? + OrdinaryGetOwnProperty(value, "length").

      4. -
      5. Let outputProto be the %ArrayPrototype% intrinsic object in - targetRealm.

      6. +
      7. Let inputLen be inputLenDescriptor.[[Value]].

      8. -
      9. Let output be ! ArrayCreate(inputLen, - outputProto).

      10. +
      11. Set serialized to { [[Type]]: "Array", [[Length]]: inputLen, + [[Properties]]: a new empty List }.

      12. + +
      13. Set deep to true.

      14. +
      +
    42. + +
    43. +

      Otherwise, if value is a platform object that is a serializable object:

      + +
        +
      1. If value has a [[Detached]] internal slot whose value is true, + then throw a "DataCloneError" DOMException.

      2. -
      3. Set deepClone to true.

      4. +
      5. Let typeString be the identifier of the primary interface of + value.

      6. + +
      7. Set serialized to { [[Type]]: typeString }.

      8. + +
      9. Set deep to true.

    44. -
    45. Otherwise, if input has a [[Clone]]() internal method, then let - output be ? input.[[Clone]](targetRealm, memory).

    46. +
    47. Otherwise, if value is a platform object, then throw a + "DataCloneError" DOMException.

    48. -
    49. Otherwise, if IsCallable(input) is true, then throw a +

    50. Otherwise, if IsCallable(value) is true, then throw a "DataCloneError" DOMException.

    51. -

      Otherwise, if input has any internal slot other than [[Prototype]] or +

      Otherwise, if value has any internal slot other than [[Prototype]] or [[Extensible]], then throw a "DataCloneError" DOMException.

      @@ -7906,117 +7976,126 @@ interface DOMStringList {
    52. -

      Otherwise, if input is an exotic object, then throw a +

      Otherwise, if value is an exotic object, then throw a "DataCloneError" DOMException.

      For instance, a proxy object.

      -
    53. +
    54. Otherwise:

        -
      1. Let output be a new Object in targetRealm.

      2. +
      3. Set serialized to { [[Type]]: "Object", [[Properties]]: a new empty List }.

      4. -
      5. Set deepClone to true.

      6. +
      7. Set deep to true.

    55. -
    56. Create an entry in memory whose key is input and value is - output.

    57. +
    58. Set memory[value] to + serialized.

    59. -

      If deepClone is true, then:

      +

      If deep is true, then:

      1. -

        If input has a [[MapData]] internal slot, then: +

        If value has a [[MapData]] internal slot, then:

          -
        1. Let inputList the value of input's [[MapData]] internal - slot.

        2. -
        3. Let copiedList be a new empty List.

        4. -

          Repeat for each Record { [[Key]], [[Value]] } entry that is an - element of inputList,

          +

          For each Record { [[Key]], [[Value]] } + entry of value.[[MapData]]:

            -
          1. Let copiedEntry be a new Record { - [[Key]]: entry.[[Key]], - [[Value]]: entry.[[Value]] }.

          2. +
          3. Let copiedEntry be a new Record { [[Key]]: + entry.[[Key]], [[Value]]: entry.[[Value]] }.

          4. -
          5. If copiedEntry.[[Key]] is not empty, append copiedEntry as the - last element of copiedList.

          6. +
          7. If copiedEntry.[[Key]] is not the special value empty, append copiedEntry to copiedList.

          - -
        5. Let outputList be the value of output's [[MapData]] internal - slot.

        6. +
        7. -

          For each Record { [[Key]], [[Value]] } entry that is an element - of copiedList,

          +

          For each Record { [[Key]], [[Value]] } + entry of copiedList:

            -
          1. Let outputKey be ? StructuredClone(entry.[[Key]], - targetRealm, memory).

          2. +
          3. Let serializedKey be ? + StructuredSerialize(entry.[[Key]], memory).

          4. -
          5. Let outputValue be ? - StructuredClone(entry.[[Value]], targetRealm, - memory).

          6. +
          7. Let serializedValue be ? + StructuredSerialize(entry.[[Value]], memory).

          8. -
          9. Add { [[Key]]: outputKey, [[Value]]: outputValue } as the last - element of outputList.

          10. +
          11. Append { [[Key]]: serializedKey, + [[Value]]: serializedValue } to serialized.[[MapData]].

      2. -

        Otherwise, if input has a [[SetData]] internal slot, then:

        +

        Otherwise, if value has a [[SetData]] internal slot, then:

          -
        1. Let copiedList be a copy of the value of input's [[SetData]] - internal slot.

        2. +
        3. Let copiedList be a new empty List. + +

        4. +

          For each entry of value.[[SetData]]:

          -
        5. Let outputList be the value of output's [[SetData]] internal - slot.

        6. +
            +
          1. If entry is not the special value empty, append entry to copiedList.

          2. +
          +
        7. -

          For each entry that is an element of copiedList that is not - empty,

          +

          For each entry of copiedList:

            -
          1. Let outputEntry be ? StructuredClone(entry, - targetResult, memory).

          2. +
          3. Let serializedEntry be ? + StructuredSerialize(entry, memory).

          4. -
          5. Add outputEntry as the last element of outputList.

          6. +
          7. Append serializedEntry to + serialized.[[SetData]].

      3. +
      4. +

        Otherwise, if value is a platform object that is a serializable object, then perform the appropriate + serialization steps given value and serialized.

        + +

        The serialization steps may need to perform a sub-serialization. This is an operation which takes as input a value + subValue, and returns StructuredSerialize(subValue, + memory). (In other words, a sub-serialization is a specialization of + StructuredSerialize to be consistent within this invocation.)

        +
      5. +
      6. Otherwise:

          -
        1. Let enumerableKeys be a new empty List.

        2. +
        3. Let enumerableKeys be a new empty List.

        4. -

          For each key in ! input.[[OwnPropertyKeys]]():

          +

          For each key in ! value.[[OwnPropertyKeys]]():

          1. If Type(key) is String, then:

              -
            1. Let inputDesc be ! - input.[[GetOwnProperty]](key).

            2. +
            3. Let inputDesc be ! value.[[GetOwnProperty]](key).

            4. -
            5. If inputDesc.[[Enumerable]] is true, then add key as the - last element of enumerableKeys.

            6. +
            7. If inputDesc.[[Enumerable]] is true, then append key to enumerableKeys.

          @@ -8027,18 +8106,18 @@ interface DOMStringList {
          1. -

            If ! HasOwnProperty(input, key) is true, then:

            +

            If ! HasOwnProperty(value, key) is true, then:

              -
            1. Let inputValue be ? input.[[Get]](key, - input).

            2. +
            3. Let inputValue be ? value.[[Get]](key, + value).

            4. Let outputValue be ? - StructuredClone(inputValue, targetRealm, + StructuredSerialize(inputValue, targetRealm, memory).

            5. -
            6. Perform ? CreateDataProperty(output, key, - outputValue).

            7. +
            8. Append { [[Key]]: key, [[Value]]: + outputValue } to serialized.[[Properties]].

          @@ -8054,87 +8133,541 @@ interface DOMStringList {
      7. -
      8. Return output.

      9. +
      10. Return serialized.

      -

      In general implementations will need to use some kind of serialization and - marshalling to implement the creation of objects in targetRealm, as - targetRealm could be in a different event loop and not easily accessible - to the code that invokes StructuredCloneWithTransfer or - StructuredClone.

      +
      +

      It's important to realize that the Records + produced by StructuredSerialize might contain "pointers" to other records that + create circular references. For example, when we pass the following JavaScript object into + StructuredSerialize:

      -

      IsTransferable ( O )

      +
      const o = {};
      +o.myself = o;
      + +

      it produces the following result:

      + +
      {
      +  [[Type]]: "Object",
      +  [[Properties]]: «
      +    {
      +      [[Key]]: "myself",
      +      [[Value]]: <a pointer to this whole structure>
      +    }
      +  »
      +}
      +
      + + +

      StructuredDeserialize ( serialized, + targetRealm [ , memory ] )

      + +

      The StructuredDeserialize abstract operation takes as input a Record + serialized, which was previously produced by StructuredSerialize, and + deserializes it into a new JavaScript value, created in targetRealm.

      + +

      This process may throw an exception, for example when trying to allocate memory for the new + objects (especially ArrayBuffer objects).

        -
      1. Assert: Type(O) is Object.

      2. +
      3. +

        If memory was not supplied, let memory be an empty map.

        + +

        The purpose of the memory map is to avoid deserializing objects + twice. This ends up preserving cycles and the identity of duplicate objects in graphs.

        +
      4. + +
      5. If memory[serialized] exists, then + return memory[serialized].

      6. + +
      7. Let deep be false.

      8. + +
      9. Let value be an uninitialized value.

      10. -

        If O has an [[ArrayBufferData]] internal slot, then:

        +

        If serialized contains a [[TransferConsumed]] field, then:

          -
        1. If IsDetachedBuffer(O) is true, then return false.

        2. +
        3. Assert: serialized.[[TransferConsumed]] is false. (It must be impossible to + get in a situation where StructuredDeserialize is being called multiple times on + the same serialization, if that serialization contains transfer data holders.)

        4. -
        5. Return true.

        6. +
        7. Set serialized.[[TransferConsumed]] to true.

        8. + +
        9. +

          If serialized.[[Type]] is "ArrayBuffer", then set value to a new + ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is + serialized.[[ArrayBufferData]], and whose [[ArrayBufferByteLength]] internal slot + value is serialized.[[ArrayBufferByteLength]].

          + +

          In cases where the original memory occupied by [[ArrayBufferData]] is + accessible during the deserialization, this step is unlikely to throw an exception, as no new + memory needs to be allocated: the memory occupied by [[ArrayBufferData]] is instead just + getting transferred into the new ArrayBuffer. This could be true, for example, when both the + source and target Realms are in the same process.

          +
        10. + +
        11. +

          Otherwise:

          + +
            +
          1. Let interfaceName be serialized.[[Type]].

          2. + +
          3. If the interface identified by interfaceName is not exposed in + targetRealm, then throw a "DataCloneError" + DOMException.

          4. + +
          5. Set value to a new instance of the interface identified by + interfaceName, created in targetRealm.

          6. + +
          7. Perform the appropriate transfer-receiving steps for the interface + identified by interfaceName given serialized and + value.

          8. +
          +
      11. +
      12. Otherwise, if serialized.[[Type]] is "primitive", then set value to + serialized.[[Value]].

        + +
      13. Otherwise, if serialized.[[Type]] is "Boolean", then set value to a new Boolean object in + targetRealm whose [[BooleanData]] internal slot value is + serialized.[[BooleanData]].

      14. + +
      15. Otherwise, if serialized.[[Type]] is "Number", then set value to a new Number object in + targetRealm whose [[NumberData]] internal slot value is + serialized.[[NumberData]].

      16. + +
      17. Otherwise, if serialized.[[Type]] is "String", then set value to a new String object in + targetRealm whose [[StringData]] internal slot value is + serialized.[[StringData]].

      18. + +
      19. Otherwise, if serialized.[[Type]] is "Date", then set value to a new Date object in + targetRealm whose [[DateValue]] internal slot value is + serialized.[[DateValue]].

      20. + +
      21. Otherwise, if serialized.[[Type]] is "RegExp", then set value to a new RegExp object in + targetRealm whose [[RegExpMatcher]] internal slot value is + serialized.[[RegExpMatcher]], whose [[OriginalSource]] internal slot value is + serialized.[[OriginalSource]], and whose [[OriginalFlags]] internal slot value is + serialized.[[OriginalFlags]].

      22. + +
      23. +

        Otherwise, if serialized.[[Type]] is "ArrayBuffer", then set value to a new ArrayBuffer + object in targetRealm whose [[ArrayBufferData]] internal slot value is + serialized.[[ArrayBufferData]], and whose [[ArrayBufferByteLength]] internal slot + value is serialized.[[ArrayBufferByteLength]].

        + +

        This step might throw an exception if there is not enough memory available to + create such an ArrayBuffer object.

        +
      24. +
      25. -

        Otherwise, if O has a [[Detached]] internal slot, then:

        +

        Otherwise, if serialized.[[Type]] is "ArrayBufferView", then:

          -
        1. If O's [[Detached]] internal slot value is true, then return - false.

        2. +
        3. Let deserializedArrayBuffer be ? + StructuredDeserialize(input.[[ArrayBufferSerialized]], + targetRealm, memory).

        4. -
        5. Return true.

        6. +
        7. If input.[[Constructor]] is "DataView", then set value to a new DataView object in + targetRealm whose [[ViewedArrayBuffer]] internal slot value is + deserializedArrayBuffer, whose [[ByteLength]] internal slot value is + serialized.[[ByteLength]], and whose [[ByteOffset]] internal slot value is + serialized.[[ByteOffset]].

        8. + +
        9. Otherwise, set value to a new typed array object, using the constructor given by + input.[[Constructor]], whose [[ViewedArrayBuffer]] internal slot value is + deserializedArrayBuffer, whose [[TypedArrayName]] internal slot value is + input.[[Constructor]], whose [[ByteLength]] internal slot value is + serialized.[[ByteLength]], whose [[ByteOffset]] internal slot value is + serialized.[[ByteOffset]], and whose [[ArrayLength]] internal slot value is + serialized.[[ArrayLength]].

      26. -
      27. Return false.

      28. +
      29. +

        Otherwise, if serialized.[[Type]] is "Map", then:

        + +
          +
        1. Set value to a new Map object in targetRealm whose [[MapData]] + internal slot value is a new empty List.

        2. + +
        3. Set deep to true.

        4. +
        +
      30. + +
      31. +

        Otherwise, if serialized.[[Type]] is "Set", then:

        + +
          +
        1. Set value to a new Set object in targetRealm whose [[SetData]] + internal slot value is a new empty List.

        2. + +
        3. Set deep to true.

        4. +
        +
      32. + +
      33. +

        Otherwise, if serialized.[[Type]] is "Array", then:

        + +
          +
        1. Let outputProto be the %ArrayPrototype% intrinsic object in + targetRealm.

        2. + +
        3. Set value to ! ArrayCreate(serialized.[[Length]], + outputProto).

        4. + +
        5. Set deep to true.

        6. +
        +
      34. + +
      35. +

        Otherwise, if serialized.[[Type]] is "Object", then:

        + +
          +
        1. Set value to a new Object in targetRealm.

        2. + +
        3. Set deep to true.

        4. +
        +
      36. + +
      37. +

        Otherwise:

        + +
          +
        1. Let interfaceName be serialized.[[Type]].

        2. + +
        3. If the interface identified by interfaceName is not exposed in + targetRealm, then throw a "DataCloneError" + DOMException.

        4. + +
        5. Set value to a new instance of the interface identified by + interfaceName, created in targetRealm.

          + +
        6. Set deep to true.

        7. +
        +
      38. + +
      39. Set memory[serialized] to + value.

      40. + +
      41. +

        If deep is true, then:

        + +
          +
        1. +

          If serialized.[[Type]] is "Map", then:

          + +
            +
          1. +

            For each Record { [[Key]], [[Value]] } + entry of serialized.[[MapData]]:

            + +
              +
            1. Let deserializedKey be ? + StructuredDeserialize(entry.[[Key]], targetRealm, + memory).

            2. + +
            3. Let deserializedValue be ? + StructuredDeserialize(entry.[[Value]], targetRealm, + memory).

            4. + +
            5. Append { [[Key]]: deserializedKey, + [[Value]]: deserializedValue } to value.[[MapData]].

            6. +
            +
          2. +
          +
        2. + +
        3. +

          Otherwise, if serialized.[[Type]] is "Set", then:

          + +
            +
          1. +

            For each entry of + serialized.[[SetData]]:

            + +
              +
            1. Let deserializedEntry be ? + StructuredDeserialize(entry, targetRealm, + memory).

            2. + +
            3. Append deserializedEntry to + value.[[SetData]].

            4. +
            +
          2. +
          +
        4. + +
        5. +

          Otherwise, if serialized.[[Type]] is "Array" or "Object", then:

          + +
            +
          1. +

            For each Record { [[Key]], [[Value]] } + entry of serialized.[[Properties]]:

            + +
              +
            1. Let deserializedValue be ? + StructuredDeserialize(entry.[[Value]], targetRealm, + memory).

            2. + +
            3. Let result be ! CreateDataProperty(value, + entry.[[Key]], deserializedValue).

            4. + +
            5. Assert: result is true.

            6. +
            +
          2. +
          +
        6. + +
        7. +

          Otherwise:

          + +
            +
          1. +

            Perform the appropriate deserialization steps for the interface identified + by serialized.[[Type]], given serialized and value.

            + +

            The deserialization steps may need to perform a sub-deserialization. This is an operation which takes as input a + previously-serialized Record subSerialized, and returns + StructuredDeserialize(subSerialized, targetRealm, + memory). (In other words, a sub-deserialization is a specialization + of StructuredDeserialize to be consistent within this invocation.)

            +
          2. +
          +
        +
      42. + +
      43. Return value.

      -

      Transfer ( input, targetRealm )

      +

      StructuredSerializeWithTransfer ( value, + transferList )

      1. -

        If input has an [[ArrayBufferData]] internal slot, then:

        +

        Let memory be an empty map.

        + +

        In addition to how it is used normally by StructuredSerialize, in + this algorithm memory is also used to ensure that StructuredSerialize + ignores items in transferList, and let us do our own handling instead.

        +
      2. + +
      3. +

        For each transferable of + transferList:

          -
        1. Let output be a new ArrayBuffer object in targetRealm whose - [[ArrayBufferByteLength]] internal slot value is the [[ArrayBufferByteLength]] internal slot - value of input, and whose [[ArrayBufferData]] internal slot value is the - [[ArrayBufferData]] internal slot value of input.

        2. +
        3. If transferable has neither an [[ArrayBufferData]] internal slot nor a + [[Detached]] internal slot, then throw a + "DataCloneError" DOMException.

        4. + +
        5. If transferable has an [[ArrayBufferData]] internal slot and ! + IsDetachedBuffer(transferable) is true, then throw a + "DataCloneError" DOMException.

        6. + +
        7. If transferable has a [[Detached]] internal slot and + transferable.[[Detached]] is true, then throw a + "DataCloneError" DOMException.

        8. + +
        9. Let placeholder be a user-agent-defined placeholder object.

        10. + +
        11. Set memory[transferable] to + placeholder.

        12. +
        +
      4. + +
      5. Let serialized be ? StructuredSerialize(input, + memory).

      6. + +
      7. Let transferDataHolders be a new empty List.

      8. + +
      9. +

        For each transferable of + transferList:

        + +
          +
        1. Let placeholder be memory[transferable].

        2. + +
        3. Let dataHolder be an uninitialized value.

        4. + +
        5. +

          If transferable has an [[ArrayBufferData]] internal slot, then:

          + +
            +
          1. Set dataHolder to { [[TransferConsumed]]: false, [[Type]]: "ArrayBuffer", + [[ArrayBufferData]]: transferable.[[ArrayBufferData]], [[ArrayBufferByteLength]]: + transferable.[[ArrayBufferByteLength]] }.

          2. + +
          3. Perform ! DetachArrayBuffer(transferable).

          4. +
          +
        6. + +
        7. +

          Otherwise:

          + +
            +
          1. Assert: transferable is a platform object that is a transferable object.

          2. + +
          3. Let interfaceName be the identifier of the primary interface + of transferable.

          4. + +
          5. Set dataHolder to { [[TransferConsumed]]: false, [[Type]]: + interfaceName }.

          6. + +
          7. Perform the appropriate transfer steps for the interface identified by + interfaceName, given transferable and dataHolder.

          8. + +
          9. Set transferable.[[Detached]] to true.

          10. +
          +
        8. + +
        9. Within serialized, replace all instances of placeholder with + dataHolder.

        10. + +
        11. Append dataHolder to + transferDataHolders.

        12. +
        +
      10. + +
      11. Return { [[Serialized]]: serialized, [[TransferDataHolders]]: + transferDataHolders }.

      12. +
      + +

      StructuredDeserializeWithTransfer ( + serializeWithTransferResult, targetRealm )

      + +
        +
      1. +

        Let memory be an empty map.

        + +

        In addition to how it is used normally by StructuredDeserialize, in + this algorithm memory is also used to help us determine the list of transferred + values.

        +
      2. + +
      3. Let deserialized be ? + StructuredDeserialize(serializeWithTransferResult.[[Serialized]], + targetRealm, memory).

      4. + +
      5. Let transferredValues be a new empty List.

      6. -
      7. Perform ! DetachArrayBuffer(input).

      8. +
      9. +

        For each transferDataHolder of + serializeWithTransferResult.[[TransferDataHolders]]:

        -
      10. Return output.

      11. +
          +
        1. Append + memory[transferDataHolder] to transferredValues.

        -
      12. Return ? input.[[Transfer]](targetRealm).

      13. +
      14. Return { [[Deserialized]]: deserialized, [[TransferredValues]]: + transferredValues }.

      15. +
      + + +

      StructuredCloneWithTransfer ( value, + transferList, targetRealm )

      + +
        +
      1. Let serializeWithTransferResult be ? + StructuredSerializeWithTransfer(value, transferList).

      2. + +
      3. Return ? + StructuredDeserializeWithTransfer(serializeWithTransferResult, + targetRealm).

      -

      Performing structured clones from other specifications

      +

      Performing serialization and + transferring from other specifications

      + +

      Other specifications may use the abstract operations defined here. The following provides + some guidance on when each abstract operation is typically useful, with examples.

      + +
      +
      StructuredCloneWithTransfer
      +
      +

      Cloning a value into a known target JavaScript Realm, with a transfer list.

      + +

      window.postMessage() uses + StructuredCloneWithTransfer to allow cloning and transferring values between + different globals.

      +
      + +
      StructuredSerializeWithTransfer
      +
      StructuredDeserializeWithTransfer
      +
      +

      Cloning a value to another JavaScript Realm, with a transfer list, but where the + target Realm is not known ahead of time. In this case the serialization step can be performed + immediately, with the deserialization step delayed until the target Realm becomes known.

      + +

      messagePort.postMessage() + uses this pair of abstract operations, as the destination Realm is not known until the + MessagePort has been shipped.

      +
      + +
      StructuredSerialize
      +
      StructuredDeserialize
      +
      +

      Creating a JavaScript Realm-independent snapshot of a given value which can be + saved for an indefinite amount of time, and then reified back into a JavaScript value later, + possibly multiple times.

      -

      Other specifications may use the StructuredClone, - StructuredCloneWithTransfer, IsTransferable, and Transfer abstract operations.

      +

      history.pushState() and history.replaceState() use + StructuredSerialize on author-supplied state objects, storing them as + serialized state in the appropriate session history entry. Then, + StructuredDeserialize is used so that the history.state property can return a clone of the + originally-supplied state object.

      + +

      broadcastChannel.postMessage() uses + StructuredSerialize on its input, then uses StructuredDeserialize + multiple times on the result to produce a fresh clone for each destination being broadcast + to. Note that transferring does not make sense in multi-destination situations.

      + +

      Any API for persisting JavaScript values to the filesystem would likely use + these.

      +
      +

      In general, call sites may pass in Web IDL values instead of JavaScript values; this is to be understood to perform an implicit conversion to the JavaScript value before invoking these algorithms.

      +

      This specification used + to define a "structured clone" algorithm, and more recently a StructuredClone abstract operation. + However, in practice all known uses of it were better served by separate serialization and + deserialization steps, so it was removed.

      + +
      +

      Call sites that are not invoked as a result of author code synchronously calling into a user agent method must take care to properly prepare to run script and prepare to - run a callback before invoking these abstract operations, if they are being performed on - arbitrary objects. This is necessary because the StructuredClone operation can invoke - author-defined accessors as part of its final deep-cloning steps, and these accessors could call - into operations that rely on the entry and before invoking StructuredCloneWithTransfer, + StructuredSerialize, or StructuredSerializeWithTransfer abstract + operations, if they are being performed on arbitrary objects. This is necessary because the + serialization process can invoke author-defined accessors as part of its final deep-serialization + steps, and these accessors could call into operations that rely on the entry and incumbent concepts being properly set up.

      -

      postMessage performs +

      window.postMessage() performs StructuredCloneWithTransfer on its arguments, but is careful to do so immediately, inside the synchronous portion of its algorithm. Thus it is able to use the structured cloning algorithms without needing to prepare to run script and prepare to run a @@ -8142,52 +8675,108 @@ interface DOMStringList {

      Parsing URLs can happen at a variety of times that are not the synchronous result of author code. However, the URL parser only applies - StructuredClone to Blob objects, so it is not in danger of running + StructuredSerialize to Blob objects, so it is not in danger of running author code with incorrect entry and incumbent values, and thus it too does not need to perform these preparation steps.

      -

      In contrast, a hypothetical API that used StructuredClone to +

      In contrast, a hypothetical API that used StructuredSerialize to serialize some author-supplied object periodically, directly from a task on the event loop, would need to ensure it performs - the appropriate preparations before calling into the structured clone algorithms. As of this time, - we know of no such APIs on the platform; usually it is simpler to perform the clone ahead of time, - as a synchronous consequence of author code, like postMessage.

      + the appropriate preparations beforehand. As of this time, we know of no such APIs on the platform; + usually it is simpler to perform the serialization ahead of time, as a synchronous consequence of + author code.

      Monkey patch for Blob and FileList objects

      -

      This monkey patch will be removed in due course. See This monkey patch will be moved in due course. See w3c/FileAPI issue 32.

      -

      Blob objects are cloneable objects.

      +

      Blob objects are serializable objects. The Blob + interface must be annotated with the [Serializable] + extended attribute. Their serialization steps, given value + and serialized, are:

      + +
        +
      1. Set serialized.[[SnapshotState]] to value's snapshot + state.

      2. + +
      3. Set serialized.[[ByteSequence]] to value's underlying byte + sequence.

      4. +
      -

      Each Blob object's [[Clone]](targetRealm, - memory) internal method must run these steps:

      +

      Their deserialization steps, given serialized and value, + are:

        -
      1. If this is closed, then throw a - "DataCloneError" DOMException.

      2. +
      3. Set value's snapshot state to + serialized.[[SnapshotState]].

      4. -
      5. Return a new instance of this in targetRealm, corresponding to the - same underlying data.

      6. +
      7. Set value's underlying byte sequence to + serialized.[[ByteSequence]].

      -

      FileList objects are cloneable objects.

      +
      -

      Each FileList object's [[Clone]](targetRealm, memory) internal method - must run these steps:

      +

      File objects are serializable objects. The File + interface must be annotated with the [Serializable] + extended attribute. Their serialization steps, given value + and serialized, are:

        -
      1. Let output be a new FileList object in - targetRealm.

      2. +
      3. Set serialized.[[SnapshotState]] to value's snapshot + state.

      4. -
      5. For each file in this, add ? - StructuredClone(file, targetRealm, memory) to the - end of the list of File objects of output.

      6. +
      7. Set serialized.[[ByteSequence]] to value's underlying byte + sequence.

      8. -
      9. Return output.

      10. +
      11. Set serialized.[[Name]] to the value of value's name attribute.

      12. + +
      13. Set serialized.[[LastModified]] to the value of value's lastModified attribute.

      14. +
      + +

      Their deserialization steps, given serialized and value, + are:

      + +
        +
      1. Set value's snapshot state to + serialized.[[SnapshotState]].

      2. + +
      3. Set value's underlying byte sequence to + serialized.[[ByteSequence]].

      4. + +
      5. Initialize the value of value's name + attribute to serialized.[[Name]].

      6. + +
      7. Initialize the value of value's lastModified attribute to + serialized.[[LastModified]].

      8. +
      + +
      + +

      FileList objects are serializable objects. The FileList + interface must be annotated with the [Serializable] + extended attribute. Their serialization steps, given value + and serialized, are:

      + +
        +
      1. Set serialized.[[Files]] to an empty list.

      2. + +
      3. For each file in value, append + the sub-serialization of file to + serialized.[[Files]].

      4. +
      + +

      Their deserialization steps, given serialized and value, + are:

      + +
        +
      1. For each file of + serialized.[[Files]], add the sub-deserialization of file to + value.

      @@ -21727,8 +22316,8 @@ interface HTMLHyperlinkElementUtils { data-x="concept-hyperlink-url-set">set the url.

      This is only observable for blob: URLs as - parsing them involves the StructuredClone abstract - operation.

      + parsing them involves the StructuredSerialize + abstract operation.

      An element implementing the HTMLHyperlinkElementUtils mixin has an associated reinitialize url algorithm, which runs these @@ -59645,7 +60234,8 @@ interface TextMetrics { [Constructor(unsigned long sw, unsigned long sh), Constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh), - Exposed=(Window,Worker)] + Exposed=(Window,Worker), + Serializable] interface ImageData { readonly attribute unsigned long width; readonly attribute unsigned long height; @@ -63605,25 +64195,6 @@ v6DVT (also check for '- -' bits in the part above) --> createImageData() methods are used to instantiate new ImageData objects.

      -

      ImageData objects are cloneable objects.

      - -

      Each ImageData object's [[Clone]](targetRealm, - memory) internal method must run these steps:

      - -
        -
      1. Let inputData be the value of this's data attribute.

      2. - -
      3. Let clonedData be ? StructuredClone(inputData, - targetRealm, memory).

      4. - -
      5. Return the result of creating an - ImageData object, with parameter pixelsPerRow set to the value of - this's width attribute, rows set to - the value of this's height attribute, and using - clonedData.

      6. -
      -

      When the ImageData() constructor is invoked with two numeric arguments sw and sh, it must create an ImageData object with parameter pixelsPerRow set to sw, and rows set @@ -63726,7 +64297,7 @@ v6DVT (also check for '- -' bits in the part above) --> steps:

        -
      1. Let imageData be a new uninitialized ImageData object.

      2. +
      3. Let imageData be a new uninitialized ImageData object.

      4. If source is specified, then assign the data attribute of imageData to @@ -63756,6 +64327,34 @@ v6DVT (also check for '- -' bits in the part above) -->

      5. Return imageData.

      +

      ImageData objects are serializable objects. Their serialization + steps, given value and serialized, are:

      + +
        +
      1. Set serialized.[[Data]] to the sub-serialization of the value of + value's data attribute.

      2. + +
      3. Set serialized.[[Width]] to the value of value's width attribute.

      4. + +
      5. Set serialized.[[Height]] to the value of value's height attribute.

      6. +
      + +

      Their deserialization steps, given serialized and value, + are:

      + +
        +
      1. Initialize value's data attribute + to the sub-deserialization of serialized.[[Data]].

      2. + +
      3. Initialize value's width attribute + to serialized.[[Width]].

      4. + +
      5. Initialize value's height attribute + to serialized.[[Height]].

      6. +
      +

      A Canvas Pixel ArrayBuffer is an ArrayBuffer whose data is represented in left-to-right order, row by row top to bottom, starting with the top left, with each pixel's red, green, blue, and alpha @@ -64795,7 +65394,7 @@ dictionary ImageEncodeOptions { enum OffscreenRenderingContextType { "2d", "webgl" }; -[Constructor([EnforceRange] unsigned long long width, [EnforceRange] unsigned long long height), Exposed=(Window,Worker)] +[Constructor([EnforceRange] unsigned long long width, [EnforceRange] unsigned long long height), Exposed=(Window,Worker), Transferable] interface OffscreenCanvas : EventTarget { attribute unsigned long long width; attribute unsigned long long height; @@ -64890,46 +65489,49 @@ interface OffscreenCanvas : EventTarget { data-x="dom-OffscreenCanvas-height">height attributes initialized to width and height respectively.

      -

      OffscreenCanvas objects are transferable.

      +
      -

      An OffscreenCanvas object's [[Transfer]](targetRealm) internal method must run these - steps:

      +

      OffscreenCanvas objects are transferable. Their transfer steps, given value and + dataHolder, are as follows:

        -
      1. If this OffscreenCanvas object's context mode is not equal to none, then throw an +

      2. If value's context mode is + not equal to none, then throw an "InvalidStateError" DOMException.

      3. -
      4. Let new be a new OffscreenCanvas object in - targetRealm.

      5. +
      6. Set value's context mode to + detached.

      7. -
      8. Initialize new's bitmap to a - rectangular array of transparent black pixels of the same dimensions as this - OffscreenCanvas object's

        Let width and height be the dimensions of value's bitmap.

      9. -
      10. If this OffscreenCanvas object has a placeholder canvas element, then set - new's placeholder canvas - element to be a weak reference to this OffscreenCanvas object's placeholder canvas element.

      11. +
      12. Unset value's bitmap.

      13. -
      14. Set this OffscreenCanvas object's [[Detached]] internal slot value to - true.

      15. +
      16. Set dataHolder.[[With]] to width, and + dataHolder.[[Height]] to height.

      17. -
      18. Set this OffscreenCanvas object's context mode to detached.

      19. +
      20. Set dataHolder.[[PlaceholderCanvas]] to be a weak reference to + value's placeholder canvas + element, if value has one, or null if it does not.

      21. +
      -
    60. Unset this OffscreenCanvas object's bitmap.

    61. +

      Their transfer-receiving steps, given dataHolder and value, + are:

      + +
        +
      1. Initialize value's bitmap to a + rectangular array of transparent black pixels with width given by dataHolder.[[Width]] + and height given by dataHolder.[[Height]].

      2. -
      3. Return new.

      4. +
      5. If dataHolder.[[PlaceholderCanvas]] is not null, set value's placeholder canvas element to + dataHolder.[[PlaceholderCanvas]] (while maintaining the weak reference + semantics).

      +
      +

      The getContext(contextId, arguments...) method of an OffscreenCanvas object, when invoked, must run the steps in the cell of the following table whose column header describes the @@ -79732,9 +80334,10 @@ callback FrameRequestCallback = void (DOMHighResTimeStampnested browsing contexts, has a distinct session history. A browsing context's session history consists of a flat list of session history entries. Each session history entry consists, at a - minimum, of a URL, and each entry may in addition have a state object, a - title, a Document object, form data, a scroll restoration mode, a scroll - position, a browsing context name, and other information associated with it.

      + minimum, of a URL, and each entry may in addition have serialized state, + a title, a Document object, form data, a scroll restoration mode, a + scroll position, a browsing context name, and other information associated with + it.

      Each entry, when first created, has a Document. However, when a Document is not active, it's possible for it to be @@ -79748,8 +80351,8 @@ callback FrameRequestCallback = void (DOMHighResTimeStampDocument. The title of a session history entry is intended to explain the state of the document at that point, so that the user can navigate the document's history.

      -

      URLs without associated state objects are added to the - session history as the user (or script) navigates from page to page.

      +

      URLs without associated serialized state are added to the session history as the + user (or script) navigates from page to page.


      @@ -79768,22 +80371,26 @@ callback FrameRequestCallback = void (DOMHighResTimeStamp -

      A state object is an object representing a user interface state.

      +

      Serialized state is a serialization (via + StructuredSerialize) of an object representing a user interface state. We sometimes + informally refer to "state objects", which are the objects representing user interface state + supplied by the author, or alternately the objects created by deserializing (via + StructuredDeserialize) serialized state.

      -

      Pages can add state - objects to the session history. These are then returned to the - script when the user (or script) goes back in the history, thus enabling authors to use the - "navigation" metaphor even in one-page applications.

      +

      Pages can add serialized state to the + session history. These are then deserialized and returned to the script when the user (or script) goes back in the + history, thus enabling authors to use the "navigation" metaphor even in one-page applications.

      -

      State objects are intended to be used for two main purposes: - first, storing a preparsed description of the state in the URL so that in the simple - case an author doesn't have to do the parsing (though one would still need the parsing for - handling URLs passed around by users, so it's only a minor - optimization), and second, so that the author can store state that one wouldn't store in the URL - because it only applies to the current Document instance and it would have to be - reconstructed if a new Document were opened.

      +

      Serialized state is intended to be used for two main purposes: first, storing a + preparsed description of the state in the URL so that in the simple case an author + doesn't have to do the parsing (though one would still need the parsing for handling URLs passed around by users, so it's only a minor optimization). Second, so + that the author can store state that one wouldn't store in the URL because it only applies to the + current Document instance and it would have to be reconstructed if a new + Document were opened.

      An example of the latter would be something like keeping track of the precise coordinate from which a pop-up div was made to animate, so that if the user goes back, it can be @@ -79804,8 +80411,7 @@ callback FrameRequestCallback = void (DOMHighResTimeStampThe current entry is usually an entry for the URL of the Document. However, it can also be one - of the entries for state objects added to the history by that - document.

      + of the entries for serialized state added to the history by that document.

      An entry with persisted user state is one that also has user-agent defined state. This specification does not specify what kind of state can be stored.

      @@ -79833,8 +80439,8 @@ callback FrameRequestCallback = void (DOMHighResTimeStampIf unspecified, the scroll restoration mode of a new entry must be set to "auto".

      -

      Entries that consist of state objects share the same - Document as the entry for the page that was active when they were added.

      +

      Entries that contain serialized state share the same Document as the + entry for the page that was active when they were added.

      Contiguous entries that differ just by their URLs' fragments also share the same Document.

      @@ -79905,7 +80511,7 @@ interface History {
      -

      Returns the current state object.

      +

      Returns the current serialized state, deserialized into an object.

      @@ -80157,8 +80763,8 @@ interface History {
    62. Let targetRealm be this History object's relevant Realm.

    63. -
    64. Let cloned data be StructuredClone(data, - targetRealm). Rethrow any exceptions.

    65. +
    66. Let serializedData be StructuredSerialize(data). + Rethrow any exceptions.

    67. @@ -80222,11 +80828,11 @@ interface History { agent wishes to persist. The entry is then said to be an entry with persisted user state.

    68. -
    69. Add a state object entry to the session history, after the current - entry, with cloned data as the state object, the given - title as the title, new URL as the URL - of the entry, and the scroll restoration mode of the current entry in the - session history as the scroll restoration mode.

    70. +
    71. Add a session history entry entry to the session history, after the + current entry, with serializedData as the serialized + state, the given title as the title, new URL as the + URL of the entry, and the scroll restoration mode of the current + entry in the session history as the scroll restoration mode.

    72. Update the current entry to be this newly added entry.

    73. @@ -80237,8 +80843,10 @@ interface History {
        -
      1. Update the current entry in the session history so that cloned data is the entry's new state object, the given title - is the new title, and new URL is the entry's new URL.

      2. +
      3. Update the current entry in the session history so that + serializedData is the entry's new serialized state, the given + title is the new title, and new URL is the entry's new + URL.

      @@ -80259,13 +80867,11 @@ interface History { -
    74. - -

      Set history.state to - StructuredClone(cloned data, targetRealm).

      +
    75. Let state be StructuredDeserialize(serializedData, + targetRealm). If this throws an exception, ignore the exception and set + state to null.

    76. - +
    77. Set history.state to state.

    78. Set the current entry's Document object's latest entry to the current entry.

    79. @@ -82766,9 +83372,12 @@ State: <OUTPUT NAME=I>1</OUTPUT> <INPUT VALUE="Increment" TYPE=BUTTON O
    80. Let targetRealm be the current Realm Record.

    81. -
    82. If entry has a state object, then let state be - StructuredClone(entry's state object, - targetRealm). Otherwise, let state be null.

    83. +
    84. If entry has serialized state, then let state be + StructuredDeserialize(entry's serialized state, + targetRealm). If this throws an exception, ignore the exception and let + statebe null.

    85. + +
    86. Otherwise, let state be null.

    87. Set history.state to state.

    88. @@ -92155,7 +92764,7 @@ interface MimeType {

      Images

      -
      [Exposed=(Window,Worker)]
      +  
      [Exposed=(Window,Worker), Serializable, Transferable]
       interface ImageBitmap {
         readonly attribute unsigned long width;
         readonly attribute unsigned long height;
      @@ -92275,46 +92884,61 @@ dictionary ImageBitmapOptions {
         true and may be changed to false by the steps of createImageBitmap().

      -

      ImageBitmap objects are cloneable objects and transferable +


      + +

      ImageBitmap objects are serializable objects and transferable objects.

      -

      Each ImageBitmap object's [[Clone]](targetRealm, memory) internal method - must run these steps:

      +

      Their serialization steps, given value and serialized, + are:

        -
      1. If this's [[Detached]] internal slot is true, then throw a - "DataCloneError" DOMException.

      2. +
      3. Set serialized.[[BitmapData]] to a copy of value's bitmap data.

      4. -
      5. Return a new ImageBitmap object in targetRealm whose bitmap data is a copy of this's bitmap data, and whose origin-clean flag is set to the same value as - this's origin-clean flag.

      6. +
      7. Set serialized.[[OriginClean]] to true if value's origin-clean flag is set, and false + otherwise.

      -

      Each ImageBitmap object's [[Transfer]](targetRealm) internal method must run these - steps:

      +

      Their deserialization steps, given serialized and value, + are:

        -
      1. Let new be a new ImageBitmap object in targetRealm, - pointing at the same underlying bitmap data - as this.

      2. +
      3. Set value's bitmap data + to serialized.[[BitmapData]].

      4. -
      5. Set new's bitmap's origin-clean flag to the same values as - this's bitmap's origin-clean - flag.

      6. +
      7. If serialized.[[OriginClean]] is true, set value's origin-clean flag.

      8. +
      -
    89. Set this's [[Detached]] internal slot value to true.

    90. +

      Their transfer steps, given value and dataHolder, are:

      -
    91. Unset this's bitmap +

        +
      1. Set dataHolder.[[BitmapData]] to value's bitmap data.

      2. + +
      3. Set dataHolder.[[OriginClean]] to true if value's origin-clean flag is set, and false + otherwise.

      4. + +
      5. Unset value's bitmap data.

      6. +
      + +

      Their transfer-receiving steps, given dataHolder and value, + are:

      + +
        +
      1. Set value's bitmap data + to dataHolder.[[BitmapData]].

      2. -
      3. Return new.

      4. +
      5. If dataHolder.[[OriginClean]] is true, set value's origin-clean flag.

      +
      +

      An ImageBitmap object can be obtained from a variety of different objects, using the createImageBitmap() method. When invoked, the method must act as follows:

      @@ -92481,10 +93105,6 @@ dictionary ImageBitmapOptions { but zero, return a promise rejected with an "IndexSizeError" DOMException and abort these steps.

    92. -
    93. If image is closed, then return a - promise rejected with an "InvalidStateError" - DOMException and abort these steps.

    94. -
    95. Return a new promise, but continue running these steps in parallel.

    96. @@ -94771,11 +95391,11 @@ function receiver(e) {
    97. Let cloneRecord be StructuredCloneWithTransfer(message, transfer, targetRealm). Rethrow any exceptions.

    98. -
    99. Let messageClone be cloneRecord.[[Clone]].

    100. +
    101. Let messageClone be cloneRecord.[[Deserialized]].

    102. Let newPorts be a new frozen array consisting of all - MessagePort objects in cloneRecord.[[TransferList]], if any, maintaining - their relative order.

    103. + MessagePort objects in cloneRecord.[[TransferredValues]], if any, + maintaining their relative order.

    104. Return, but continue running these steps in in parallel.

    105. @@ -95073,7 +95693,7 @@ interface MessageChannel {

      Each channel has two message ports. Data sent through one port is received by the other port, and vice versa.

      -
      [Exposed=(Window,Worker)]
      +  
      [Exposed=(Window,Worker), Transferable]
       interface MessagePort : EventTarget {
         void postMessage(any message, optional sequence<object> transfer = []);
         void start();
      @@ -95201,61 +95821,53 @@ interface MessagePort : EventTarget {
       
         
    -

    MessagePort objects are transferable - objects.

    +
    -

    Each MessagePort object's [[Transfer]](targetRealm) internal method must run these - steps:

    +

    MessagePort objects are transferable + objects. Their transfer steps, given value and + dataHolder, are:

      +
    1. Set value's has been shipped flag to true.

    2. -
    3. Set this's has been shipped flag to true.

    4. - -
    5. Let new be a new - MessagePort object in targetRealm whose owner is targetRealm's settings object.

    6. - -
    7. Set new's has been shipped flag to true.

    8. - -
    9. Move all the tasks that are to fire message events in the port message queue of - this to the port message queue of new, if any, leaving - new's port message queue in its initial disabled state, and, if - new's owner specifies a responsible - event loop that is a browsing context event loop, associating - the moved tasks with the responsible document - specified by new's owner.

    10. - - +
    11. Set dataHolder.[[PortMessageQueue]] to value's port message + queue.

    12. -

      If this is entangled with another port, then run these substeps:

      +

      If value is entangled with another port remotePort, then:

        -
      1. Let remote port be the port with which this is entangled.

      2. - -
      3. Set remote port's has been shipped flag to true.

      4. +
      5. Set remotePort's has been shipped flag to true.

      6. -
      7. Entangle remote port and new. this will be - disentangled by this process.

      8. +
      9. Set dataHolder.[[RemotePort]] to remotePort.

    13. -
    14. Set this's [[Detached]] internal slot value to true.

    15. +
    16. Otherwise, set dataHolder.[[RemotePort]] to null.

    17. +
    + +

    Their transfer-receiving steps, given dataHolder and value, + are:

    + +
      +
    1. Set value's has been shipped flag to true.

    2. + +
    3. Set value's owner to value's relevant settings + object.

    4. + +
    5. Move all the tasks that are to fire message events in dataHolder.[[PortMessageQueue]] to the + port message queue of value, if any, leaving + value's port message queue in its initial disabled state, and, if + value's owner specifies a responsible + event loop that is a browsing context event loop, associating + the moved tasks with the responsible document + specified by value's owner.

    6. -
    7. Return new. It is the clone.

    8. +
    9. If dataHolder.[[RemotePort]] is not null, then entangle + dataHolder.[[RemotePort]] and value. (This will disentangle + dataHolder.[[RemotePort]] from the original port that was transferred.)


    @@ -95268,45 +95880,20 @@ interface MessagePort : EventTarget {
  • Let targetPort be the port with which this MessagePort is entangled, if any; otherwise let it be null.

  • -
  • -

    Let doomed be false.

    - -

    It is set to true if a condition is detected that will make this message cause - the port to be unusable; specifically, if the message contains target port as one of - the objects being transferred. (This condition cannot necessarily be detected when the method is - called.)

    -
  • -
  • If any of the objects in transfer are this MessagePort, then throw a "DataCloneError" DOMException and abort these steps.

  • +
  • Let doomed be false.

  • +
  • If targetPort is not null and any of the objects in transfer are targetPort, then set doomed to true, and optionally report to a developer console that the target port was posted to itself, causing the communication channel to be lost.

  • -
  • -

    Let targetRealm be targetPort's owner's Realm, if targetPort is non-null and doomed is false; - otherwise let targetRealm be some arbitrary Realm.

    - -

    targetRealm is used when cloning and transferring objects below. If - there is no target port, or if the targetPort is one of the objects being - transferred, the transferable objects given in the second argument, if any, are still - transferred, but since they are then discarded, it doesn't matter where they are transferred - to.)

    -
  • - -
  • Let cloneRecord be StructuredCloneWithTransfer(message, - transfer, targetRealm). Rethrow any exceptions.

  • - -
  • Let messageClone be cloneRecord.[[Clone]].

  • - -
  • Let newPorts be a new frozen array consisting of all - MessagePort objects in cloneRecord.[[TransferList]], if any, maintaining - their relative order.

  • +
  • Let serializeWithTransferResult be + StructuredSerializeWithTransfer(message, transfer). Rethrow + any exceptions.

  • If there is no targetPort (i.e. if this MessagePort is not entangled), or if doomed is true, then abort these steps.

  • @@ -95317,24 +95904,44 @@ interface MessagePort : EventTarget { algorithm runs scripts). We don't throw an exception for 'doomed' being true, because this can't necessarily be detected right now every time --> -
  • Let e be the result of creating an event using - MessageEvent.

  • - -
  • Initialize e's type attribute to message, its data - attribute to messageClone, and its ports - attribute to newPorts.

  • -
  • Add a task that runs the following steps to the port message queue of targetPort:

      -
    1. Let target be the MessagePort in whose port message - queue the event e now finds itself.

    2. +
    3. +

      Let finalTargetPort be the MessagePort in whose port message + queue the task now finds itself.

      + +

      This can be different from targetPort, if targetPort + itself was transferred and thus all its tasks moved along with it.

      +
    4. + +
    5. Let targetRealm be finalTargetPort's relevant Realm.

    6. + +
    7. Let deserializeRecord be + StructuredDeserializeWithTransfer(serializeWithTransferResult, + targetRealm).

    8. + + +
    9. Let messageClone be deserializeRecord.[[Deserialized]].

    10. + +
    11. Let newPorts be a new frozen array consisting of all + MessagePort objects in deserializeRecord.[[TransferredValues]], if any, + maintaining their relative order.

    12. + +
    13. Let e be the result of creating an event using + MessageEvent in targetRealm.

    14. + +
    15. Initialize e's type attribute to message, its data + attribute to messageClone, and its ports attribute to newPorts.

    16. Dispatch e at - target.

    17. + finalTargetPort.

  • @@ -95570,8 +96177,8 @@ interface BroadcastChannel : EventTarget {
  • Let targetRealm be a user-agent defined Realm.

  • -
  • Let clonedMessage be StructuredClone(message, - targetRealm). Rethrow any exceptions.

  • +
  • Let serialized be StructuredSerialize(message). Rethrow + any exceptions.

  • Let destinations be a list of BroadcastChannel objects that @@ -95619,18 +96226,20 @@ interface BroadcastChannel : EventTarget { destinations, queue a task that runs the following steps:

      -
    1. Let targetRealm be destination's relevant settings - object's Realm.

    2. +
    3. Let targetRealm be destination's relevant Realm.

    4. + +
    5. Let data be StructuredDeserialize(serialized, + targetRealm).

    6. +
    7. Fire an event named message at destination, using MessageEvent, with the data attribute - initialized to StructuredClone(clonedMessage, targetRealm) - - and the origin attribute initialized to the Unicode serialization of - sourceSettings's data and the origin + attribute initialized to the Unicode + serialization of sourceSettings's origin.