From d580c82aa1ef89111bea8461c34cad42edd79756 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 7 Mar 2017 16:51:56 -0500 Subject: [PATCH 01/40] Add StructuredSerialize() --- source | 399 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 399 insertions(+) diff --git a/source b/source index ab4428cd803..82e4b9279db 100644 --- a/source +++ b/source @@ -7647,6 +7647,107 @@ interface DOMStringList {

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

+

Serializable objects

+ +

TODO: subsume the above section.

+ +

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).

+ +

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

+ +

Platform objects have the following internal method:

+ +

[[Serialize]] ( memory )

+ +

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

+ +

Platform objects that are serializable + objects have a [[Serialize]]() internal method which is specified to run a + series of steps. These steps must conform to the following requirements:

+ + + + + +

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

+ +

Transferable objects

Transferable objects support being transferred across Transfer.)

+

StructuredSerialize ( input [ , + memory ] )

+ +

The StructuredSerialize abstract operation takes as input a JavaScript value + input 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.

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

  2. + +
  3. If memory[input] exists, then + return memory[input].

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

  6. + +
  7. If Type(input) is Symbol, then throw a + "DataCloneError" DOMException.

  8. + +
  9. Let deepSerialize be false.

  10. + +
  11. If input has a [[BooleanData]] internal slot, then let output be { + [[Type]]: "Boolean", [[BooleanData]]: input.[[BooleanData]] }.

  12. + +
  13. Otherwise, if input has a [[NumberData]] internal slot, then let + output be { [[Type]]: "Number", [[NumberData]]: input.[[NumberData]] + }.

  14. + +
  15. Otherwise, if input has a [[StringData]] internal slot, then let + output be { [[Type]]: "String", [[StringData]]: input.[[StringData]] + }.

  16. + +
  17. Otherwise, if input has a [[DateValue]] internal slot, then let + output be { [[Type]]: "Date", [[DateValue]]: input.[[DateValue]] + }.

  18. + +
  19. Otherwise, if input has a [[RegExpMatcher]] internal slot, then let + output be { [[Type]]: "RegExp", [[RegExpMatcher]]: input.[[RegExpMatcher]], + [[OriginalSource]]: input.[[OriginalSource]], [[OriginalFlags]]: + input.[[OriginalFlags]] }.

  20. + +
  21. +

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

    + +
      +
    1. If IsDetachedBuffer(input) is true, then throw a + "DataCloneError" DOMException.

    2. + +
    3. Let output be { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: + input.[[ArrayBufferData]], [[ArrayBufferByteLength]]: + input.[[ArrayBufferByteLength]] }.

    4. +
    +
  22. + +
  23. +

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

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

    2. + +
    3. Let bufferSerialized be ? StructuredSerialize(buffer, + memory).

    4. + +
    5. Assert: bufferSerialized.[[Type]] is "ArrayBuffer".

    6. + +
    7. If input has a [[DataView]] internal slot, then let output be { + [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView", [[ArrayBufferSerialized]]: + bufferSerialized, [[ByteLength]]: input.[[ByteLength]], + [[ByteOffset]]: input.[[ByteOffset]] }.

    8. + +
    9. +

      Otherwise:

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

      2. + +
      3. Let output be { [[Type]]: "ArrayBufferView", [[Constructor]]: + input.[[TypedArrayName]], [[ArrayBufferSerialized]]: bufferSerialized, + [[ByteLength]]: input.[[ByteLength]], [[ByteOffset]]: + input.[[ByteOffset]], [[ArrayLength]]: input.[[ArrayLength]] }.

      4. +
      +
    10. +
    +
  24. + +
  25. +

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

    + +
      +
    1. Let output be { [[Type]]: "Map", [[MapData]]: a new empty List }.

    2. + +
    3. Set deepSerialize to true.

    4. +
    +
  26. + +
  27. +

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

    + +
      +
    1. Let output be { [[Type]]: "Set", [[SetData]]: a new empty List }.

    2. + +
    3. Set deepSerialize to true.

    4. +
    +
  28. + +
  29. +

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

    + + +
      +
    1. Let inputLenDescriptor be ? + OrdinaryGetOwnProperty(input, "length").

    2. + +
    3. Let inputLen be inputLenDescriptor.[[Value]].

    4. + +
    5. Let output be { [[Type]]: "Array", [[Length]]: inputLen, + [[Properties]]: a new empty List }.

    6. + +
    7. Set deepSerialize to true.

    8. +
    +
  30. + +
  31. Otherwise, if input has a [[Serialize]]() internal method, then + let output be ? input.[[Serialize]](memory).

  32. + +
  33. Otherwise, if IsCallable(input) is true, then throw a + "DataCloneError" DOMException.

  34. + +
  35. +

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

    + +

    For instance, a [[PromiseState]] or [[WeakMapData]] internal slot.

    +
  36. + +
  37. +

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

    + +

    For instance, a proxy object.

    +
  38. + +
  39. +

    Otherwise:

    + +
      +
    1. Let output be { [[Type]]: "Object", [[Properties]]: a new empty List }.

    2. + +
    3. Set deepSerialize to true.

    4. +
    +
  40. + +
  41. Set memory[input] to + output.

  42. + +
  43. +

    If deepSerialize is true, then:

    + +
      +
    1. +

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

        +
      1. Let copiedList be a new empty List. + +

      2. +

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

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

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

        4. +
        +
      3. + +
      4. +

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

        + +
          +
        1. Let outputKey be ? + StructuredSerialize(entry.[[Key]], memory).

        2. + +
        3. Let outputValue be ? + StructuredSerialize(entry.[[Value]], memory).

        4. + +
        5. Append { [[Key]]: outputKey, [[Value]]: + outputValue } to output.[[MapData]].

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

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

      + +
        +
      1. Let copiedList be a new empty List. + +

      2. +

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

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

        2. +
        +
      3. + +
      4. +

        For each entry of + copiedList:

        + +
          +
        1. Let outputEntry be ? StructuredSerialize(entry, + memory).

        2. + +
        3. Append outputEntry to + outputList.

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

      Otherwise: + +

        +
      1. Let enumerableKeys be a new empty List.

      2. + +
      3. +

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

        + +
          +
        1. +

          If Type(key) is String, then:

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

          2. + +
          3. If inputDesc.[[Enumerable]] is true, then append key to enumerableKeys.

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

        For each key in enumerableKeys:

        + +
          +
        1. +

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

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

          2. + +
          3. Let outputValue be ? + StructuredSerialize(inputValue, targetRealm, + memory).

          4. + +
          5. Append { [[Key]]: key, [[Value]]: + outputValue } to output.[[Properties]].

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

      The key collection performed above is very similar to the JavaScript + specification's EnumerableOwnProperties operation, but crucially it uses the + deterministic ordering provided by the [[OwnPropertyKeys]] internal method, instead of + reordering the keys in an unspecified manner as EnumerableOwnProperties does. +

      +
    6. +
    +
  44. + +
  45. Return output.

  46. +
+

StructuredCloneWithTransfer ( input, transferList, targetRealm )

From 5c27fd493500ab2e1f5664a4c96b37d2848384a9 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 7 Mar 2017 17:37:27 -0500 Subject: [PATCH 02/40] Re-do the model for platform objects This allows circular references to work correctly --- source | 153 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 60 deletions(-) diff --git a/source b/source index 82e4b9279db..5c978fb9efb 100644 --- a/source +++ b/source @@ -7660,51 +7660,51 @@ interface DOMStringList {

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

-

Platform objects have the following internal method:

+

Platform objects can be serializable objects if they + define three things:

-

[[Serialize]] ( memory )

+
+
A serialization type string
+

A string that uniquely identifies this class of serializable objects, so that + the StructuredSerialize and StructuredDeserialize algorithms can + recognize instances of serialized data to which this definition applies.

-

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

+
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.

-

Platform objects that are serializable - objects have a [[Serialize]]() internal method which is specified to run a - series of steps. These steps must conform to the following requirements:

+

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

-
    -
  • They must either throw an exception, or return a JavaScript Record containing a [[Type]] - field whose value is a string, known as the structured serialization type string. That string must - uniquely identify the type of platform object in question, and must be the same for all instances - of the platform object produced by these steps.

  • - -
  • Any invocations of StructuredSerialize inside these steps must pass along - memory as the second argument.

  • -
+

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.

+
- - -

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

Transferable objects

@@ -7912,9 +7916,19 @@ interface DOMStringList { -
  • Otherwise, if input has a [[Serialize]]() internal method, then - let output be ? input.[[Serialize]](memory).

  • +
  • +

    Otherwise, if input is a platform object that is a + serializable object:

    + +
      +
    1. Let typeString be the serialization type string for + input.

    2. + +
    3. Let output be { [[Type]]: typeString }.

    4. + +
    5. Set deepSerialize to true.

    6. +
    +
  • Otherwise, if IsCallable(input) is true, then throw a "DataCloneError" DOMException.

  • @@ -8022,6 +8036,18 @@ interface DOMStringList { +
  • +

    Otherwise, if input is a platform object that is a + serializable object, then run the appropriate + serialization steps given input and output.

    + +

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

    +
  • +
  • Otherwise: @@ -8082,6 +8108,13 @@ interface DOMStringList {

  • Return output.

  • +

    StructuredDeserialize ( input, + targetRealm [ , memory ] )

    + +

    TODO: sub-deserialization

    + +

    StructuredCloneWithTransfer ( input, transferList, targetRealm )

    From 37e56593c39d279c7e5d183786cb0e4ab4ec9d54 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 7 Mar 2017 17:41:30 -0500 Subject: [PATCH 03/40] Change variable names from (input, output) to (value, serialized) --- source | 160 +++++++++++++++++++++++++++------------------------------ 1 file changed, 77 insertions(+), 83 deletions(-) diff --git a/source b/source index 5c978fb9efb..080d53afdb5 100644 --- a/source +++ b/source @@ -7789,66 +7789,67 @@ interface DOMStringList { IsTransferable and Transfer.)

    StructuredSerialize ( input [ , + data-dfn-type="abstract-op">StructuredSerialize ( value [ , memory ] )

    The StructuredSerialize abstract operation takes as input a JavaScript value - input and serializes it to a Realm-independent + 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.

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

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

    4. -
    5. If memory[input] exists, then - return memory[input].

    6. +
    7. If memory[value] exists, then + return memory[value].

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

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

    12. -
    13. If Type(input) is Symbol, then throw a +

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

    15. Let deepSerialize be false.

    16. -
    17. If input has a [[BooleanData]] internal slot, then let output be { - [[Type]]: "Boolean", [[BooleanData]]: input.[[BooleanData]] }.

    18. +
    19. If value has a [[BooleanData]] internal slot, then let serialized be + { [[Type]]: "Boolean", [[BooleanData]]: value.[[BooleanData]] }.

    20. -
    21. Otherwise, if input has a [[NumberData]] internal slot, then let - output be { [[Type]]: "Number", [[NumberData]]: input.[[NumberData]] +

    22. Otherwise, if value has a [[NumberData]] internal slot, then let + serialized be { [[Type]]: "Number", [[NumberData]]: value.[[NumberData]] }.

    23. -
    24. Otherwise, if input has a [[StringData]] internal slot, then let - output be { [[Type]]: "String", [[StringData]]: input.[[StringData]] +

    25. Otherwise, if value has a [[StringData]] internal slot, then let + serialized be { [[Type]]: "String", [[StringData]]: value.[[StringData]] }.

    26. -
    27. Otherwise, if input has a [[DateValue]] internal slot, then let - output be { [[Type]]: "Date", [[DateValue]]: input.[[DateValue]] +

    28. Otherwise, if value has a [[DateValue]] internal slot, then let + serialized be { [[Type]]: "Date", [[DateValue]]: value.[[DateValue]] }.

    29. -
    30. Otherwise, if input has a [[RegExpMatcher]] internal slot, then let - output be { [[Type]]: "RegExp", [[RegExpMatcher]]: input.[[RegExpMatcher]], - [[OriginalSource]]: input.[[OriginalSource]], [[OriginalFlags]]: - input.[[OriginalFlags]] }.

    31. +
    32. Otherwise, if value has a [[RegExpMatcher]] internal slot, then let + serialized be { [[Type]]: "RegExp", [[RegExpMatcher]]: + value.[[RegExpMatcher]], [[OriginalSource]]: value.[[OriginalSource]], + [[OriginalFlags]]: value.[[OriginalFlags]] }.

    33. -

      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 output be { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: - input.[[ArrayBufferData]], [[ArrayBufferByteLength]]: - input.[[ArrayBufferByteLength]] }.

      5. +
      6. Let serialized be { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: + value.[[ArrayBufferData]], [[ArrayBufferByteLength]]: + value.[[ArrayBufferByteLength]] }.

    34. -

      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. Let bufferSerialized be ? StructuredSerialize(buffer, @@ -7856,31 +7857,31 @@ interface DOMStringList {

      4. Assert: bufferSerialized.[[Type]] is "ArrayBuffer".

      5. -
      6. If input has a [[DataView]] internal slot, then let output be { - [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView", [[ArrayBufferSerialized]]: - bufferSerialized, [[ByteLength]]: input.[[ByteLength]], - [[ByteOffset]]: input.[[ByteOffset]] }.

      7. +
      8. If value has a [[DataView]] internal slot, then let serialized be + { [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView", [[ArrayBufferSerialized]]: + bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: + value.[[ByteOffset]] }.

      9. Otherwise:

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

        2. +
        3. Assert: value has a [[TypedArrayName]] internal slot.

        4. -
        5. Let output be { [[Type]]: "ArrayBufferView", [[Constructor]]: - input.[[TypedArrayName]], [[ArrayBufferSerialized]]: bufferSerialized, - [[ByteLength]]: input.[[ByteLength]], [[ByteOffset]]: - input.[[ByteOffset]], [[ArrayLength]]: input.[[ArrayLength]] }.

        6. +
        7. Let serialized be { [[Type]]: "ArrayBufferView", [[Constructor]]: + value.[[TypedArrayName]], [[ArrayBufferSerialized]]: bufferSerialized, + [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: + value.[[ByteOffset]], [[ArrayLength]]: value.[[ArrayLength]] }.

    35. -

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

      +

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

        -
      1. Let output be { [[Type]]: "Map", [[MapData]]: a new empty

        Let serialized be { [[Type]]: "Map", [[MapData]]: a new empty List }.

      2. Set deepSerialize to true.

      3. @@ -7888,10 +7889,10 @@ interface DOMStringList {
      4. -

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

        +

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

          -
        1. Let output be { [[Type]]: "Set", [[SetData]]: a new empty

          Let serialized be { [[Type]]: "Set", [[SetData]]: a new empty List }.

        2. Set deepSerialize to true.

        3. @@ -7899,17 +7900,16 @@ interface DOMStringList {
        4. -

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

          - +

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

          1. Let inputLenDescriptor be ? - OrdinaryGetOwnProperty(input, "length").

          2. + OrdinaryGetOwnProperty(value, "length").

          3. Let inputLen be inputLenDescriptor.[[Value]].

          4. -
          5. Let output be { [[Type]]: "Array", [[Length]]: inputLen, +

          6. Let serialized be { [[Type]]: "Array", [[Length]]: inputLen, [[Properties]]: a new empty List }.

          7. Set deepSerialize to true.

          8. @@ -7917,24 +7917,24 @@ interface DOMStringList {
          9. -

            Otherwise, if input is a platform object that is a - serializable object:

            +

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

            1. Let typeString be the serialization type string for - input.

            2. + value.

              -
            3. Let output be { [[Type]]: typeString }.

            4. +
            5. Let serialized be { [[Type]]: typeString }.

            6. Set deepSerialize to true.

          10. -
          11. Otherwise, if IsCallable(input) is true, then throw a +

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

          13. -

            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.

            @@ -7942,7 +7942,7 @@ interface DOMStringList {
          14. -

            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.

            @@ -7952,38 +7952,36 @@ interface DOMStringList {

            Otherwise:

              -
            1. Let output be { [[Type]]: "Object", [[Properties]]: a new empty

              Let serialized be { [[Type]]: "Object", [[Properties]]: a new empty List }.

            2. Set deepSerialize to true.

          15. -
          16. Set memory[input] to - output.

          17. +
          18. Set memory[value] to + serialized.

          19. If deepSerialize is true, then:

            1. -

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

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

              1. Let copiedList be a new empty List.

              2. For each Record { [[Key]], [[Value]] } - entry of input.[[MapData]]:

                + 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. If copiedEntry.[[Key]] is not the special value empty, append copiedEntry to - copiedList.

                5. + data-x="list append">append copiedEntry to copiedList.

              3. @@ -7999,31 +7997,29 @@ interface DOMStringList { StructuredSerialize(entry.[[Value]], memory).

              4. Append { [[Key]]: outputKey, [[Value]]: - outputValue } to output.[[MapData]].

              5. + outputValue } to serialized.[[MapData]].

          20. -

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

            +

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

            1. Let copiedList be a new empty List.

            2. -

              For each entry of - input.[[SetData]]:

              +

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

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

              2. +
              3. If entry is not the special value empty, append entry to copiedList.

            3. -

              For each entry of - copiedList:

              +

              For each entry of copiedList:

              1. Let outputEntry be ? StructuredSerialize(entry, @@ -8037,9 +8033,9 @@ interface DOMStringList {

              2. -

                Otherwise, if input is a platform object that is a - serializable object, then run the appropriate - serialization steps given input and output.

                +

                Otherwise, if value is a platform object that is a serializable object, then run 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 @@ -8052,19 +8048,17 @@ interface DOMStringList {

                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. If inputDesc.[[Enumerable]] is true, then append key to enumerableKeys.

                    5. @@ -8078,18 +8072,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 ? StructuredSerialize(inputValue, targetRealm, memory).

                        5. Append { [[Key]]: key, [[Value]]: - outputValue } to output.[[Properties]].

                        6. + outputValue } to serialized.[[Properties]].

                      @@ -8105,7 +8099,7 @@ interface DOMStringList {
                  2. -
                  3. Return output.

                  4. +
                  5. Return serialized.

                  Date: Tue, 7 Mar 2017 18:49:26 -0500 Subject: [PATCH 04/40] Deserialize done now --- source | 298 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 278 insertions(+), 20 deletions(-) diff --git a/source b/source index 080d53afdb5..9f0b1dd50ce 100644 --- a/source +++ b/source @@ -7797,6 +7797,9 @@ interface DOMStringList { 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.

                  +

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

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

                  2. @@ -7804,14 +7807,14 @@ interface DOMStringList {
                  3. If memory[value] exists, then return memory[value].

                  4. +
                  5. Let deep be false.

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

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

                  9. -
                  10. Let deepSerialize be false.

                  11. -
                  12. If value has a [[BooleanData]] internal slot, then let serialized be { [[Type]]: "Boolean", [[BooleanData]]: value.[[BooleanData]] }.

                  13. @@ -7884,7 +7887,7 @@ interface DOMStringList {
                  14. Let serialized be { [[Type]]: "Map", [[MapData]]: a new empty List }.

                  15. -
                  16. Set deepSerialize to true.

                  17. +
                  18. Set deep to true.

                5. @@ -7895,7 +7898,7 @@ interface DOMStringList {
                6. Let serialized be { [[Type]]: "Set", [[SetData]]: a new empty List }.

                7. -
                8. Set deepSerialize to true.

                9. +
                10. Set deep to true.

              3. @@ -7912,7 +7915,7 @@ interface DOMStringList {
              4. Let serialized be { [[Type]]: "Array", [[Length]]: inputLen, [[Properties]]: a new empty List }.

              5. -
              6. Set deepSerialize to true.

              7. +
              8. Set deep to true.

            4. @@ -7926,10 +7929,13 @@ interface DOMStringList {
            5. Let serialized be { [[Type]]: typeString }.

            6. -
            7. Set deepSerialize to true.

            8. +
            9. Set deep to true.

          21. +
          22. Otherwise, if value is a platform object, then throw a + "DataCloneError" DOMException.

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

          25. @@ -7955,7 +7961,7 @@ interface DOMStringList {
          26. Let serialized be { [[Type]]: "Object", [[Properties]]: a new empty List }.

          27. -
          28. Set deepSerialize to true.

          29. +
          30. Set deep to true.

        5. @@ -7963,7 +7969,7 @@ interface DOMStringList { serialized.

        6. -

          If deepSerialize is true, then:

          +

          If deep is true, then:

          1. @@ -7990,14 +7996,14 @@ interface DOMStringList { entry of copiedList:

              -
            1. Let outputKey be ? +

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

            3. -
            4. Let outputValue be ? +

            5. Let serializedValue be ? StructuredSerialize(entry.[[Value]], memory).

            6. -
            7. Append { [[Key]]: outputKey, [[Value]]: - outputValue } to serialized.[[MapData]].

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

          @@ -8022,11 +8028,11 @@ interface DOMStringList {

          For each entry of copiedList:

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

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

          4. -
          5. Append outputEntry to - outputList.

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

        @@ -8034,12 +8040,12 @@ interface DOMStringList {
      5. Otherwise, if value is a platform object that is a serializable object, then run the appropriate + data-x="serializable objects">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 - value, and returns StructuredSerialize(value, + subValue, and returns StructuredSerialize(subValue, memory). (In other words, a sub-serialization is a specialization of StructuredSerialize to be consistent within this invocation.)

      6. @@ -8102,11 +8108,263 @@ interface DOMStringList {
      7. Return serialized.

      +
      +

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

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

      it produces the following result:

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

      StructuredDeserialize ( input, + data-dfn-type="abstract-op">StructuredDeserialize ( serialized, targetRealm [ , memory ] )

      -

      TODO: sub-deserialization

      +

      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. If memory was not supplied, let memory be an empty map.

      2. + +
      3. If memory[serialized] exists, then + return memory[serialized].

      4. + +
      5. Let deep be false.

      6. + +
      7. If serialized.[[Type]] is "primitive", then let value be + serialized.[[Value]].

        + +
      8. Otherwise, if serialized.[[Type]] is "Boolean", then let value be a new Boolean object in + targetRealm whose [[BooleanData]] internal slot value is + serialized.[[BooleanData]].

      9. + +
      10. Otherwise, if serialized.[[Type]] is "Number", then let value be a new Number object in + targetRealm whose [[NumberData]] internal slot value is + serialized.[[NumberData]].

      11. + +
      12. Otherwise, if serialized.[[Type]] is "String", then let value be a new String object in + targetRealm whose [[StringData]] internal slot value is + serialized.[[StringData]].

      13. + +
      14. Otherwise, if serialized.[[Type]] is "Date", then let value be a new Date object in + targetRealm whose [[DateValue]] internal slot value is + serialized.[[DateValue]].

      15. + +
      16. Otherwise, if serialized.[[Type]] is "RegExp", then let value be 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]].

      17. + +
      18. +

        Otherwise, if serialized.[[Type]] is "ArrayBuffer", then let value be 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.

        +
      19. + +
      20. +

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

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

        2. + +
        3. If input.[[Constructor]] is "DataView", then let value be 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]].

        4. + +
        5. Otherwise, let value be 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]].

        6. +
        +
      21. + +
      22. +

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

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

        2. + +
        3. Set deep to true.

        4. +
        +
      23. + +
      24. +

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

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

        2. + +
        3. Set deep to true.

        4. +
        +
      25. + +
      26. +

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

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

        2. + +
        3. Let value be ! ArrayCreate(serialized.[[Length]], + outputProto).

        4. + +
        5. Set deep to true.

        6. +
        +
      27. + +
      28. +

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

        + +
          +
        1. Let value be a new Object in targetRealm.

        2. + +
        3. Set deep to true.

        4. +
        +
      29. + +
      30. +

        Otherwise:

        + +
          +
        1. Assert: serialized.[[Type]] is a serialization type string for a + platform object.

        2. + +
        3. Let value be a new instance of the platform object type + identified by serialized.[[Type]].

        4. + +
        5. Set deep to true.

        6. +
        +
      31. + +
      32. Set memory[serialized] to + value.

      33. + +
      34. +

        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. Perform ? CreateDataProperty(value, + entry.[[Key]], deserializedValue).

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

          Otherwise:

          + +
            +
          1. Assert: serialized.[[Type]] is a serialization type string for + a platform object.

          2. + +
          3. +

            Perform the appropriate deserialization steps 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.)

            +
          4. +
          +
        +
      35. + +
      36. Return value.

      37. +

      Date: Tue, 7 Mar 2017 19:23:23 -0500 Subject: [PATCH 05/40] OK, transfer/receivetransfer done --- source | 145 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 125 insertions(+), 20 deletions(-) diff --git a/source b/source index 9f0b1dd50ce..42b028ef8fb 100644 --- a/source +++ b/source @@ -7660,8 +7660,8 @@ interface DOMStringList {

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

      -

      Platform objects can be serializable objects if they - define three things:

      +

      Platform objects can be serializable objects + if they define three things:

      A serialization type string
      @@ -7702,8 +7702,8 @@ interface DOMStringList {

      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.

      -

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

      +

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

      Let's say we were defining a platform object Person, which had @@ -7764,30 +7764,61 @@ 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 can be transferable objects + if they define three things:

      + +
      +
      A transfer type string
      +

      A string that uniquely identifies this class of transferable objects, so that + the StructuredTransfer and StructuredReceiveTransfer algorithms + can recognize instances of data to which this definition applies.

      + +
      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.

      + +

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

      + +

      These steps may themselves call StructuredTransfer to transfer nested data + structures.

      +
      + +
      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.

      + +

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

      + +

      These steps may themselves call StructuredReceiveTransfer to receive the + transfer of nested data structures.

      +
      +
      + +

      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.

      + +

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

      +

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

      + data-dfn-type="attribute">[[Detached]] internal slot. This is used to ensure that once a + platform object has been transferred, it cannot be transferred again.

      + +

      TODO: delete the below

      [[Transfer]]( targetRealm )

      -

      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.

      - -

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

      -

      StructuredSerialize ( value [ , memory ] )

      @@ -8366,6 +8397,80 @@ interface DOMStringList {
    36. Return value.

    +

    StructuredTransfer ( value )

    + +
      +
    1. Assert: IsTransferable(value) is true.

    2. + +
    3. +

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

      + +
        +
      1. Let dataHolder be { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: + value.[[ArrayBufferData]], [[ArrayBufferByteLength]]: + value.[[ArrayBufferByteLength]] }.

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

      4. +
      +
    4. + +
    5. +

      Otherwise:

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

      2. + +
      3. Let typeString be the transfer type string for + value.

      4. + +
      5. Let dataHolder be { [[Type]]: typeString }.

      6. + +
      7. Perform the appropriate transfer steps given value and + dataHolder.

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

      10. +
      +
    6. + +
    7. Return dataHolder.

      +
    + +

    StructuredReceiveTransfer ( dataHolder, + targetRealm )

    + +
      +
    1. +

      If dataHolder.[[Type]] is "ArrayBuffer", then let value be a new + ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is + dataHolder.[[ArrayBufferData]], and whose [[ArrayBufferByteLength]] internal slot + value is dataHolder.[[ArrayBufferByteLength]].

      + +

      Unlike the corresponding step in StructuredDeserialize, 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.

      +
    2. + +
    3. +

      Otherwise:

      + +
        +
      1. Assert: dataHolder.[[Type]] is a transfer type string for a + platform object.

      2. + +
      3. Let value be a new instance of the platform object type + identified by dataHolder.[[Type]].

      4. + +
      5. Perform the appropriate transfer receive steps given dataHolder + and value.

      6. +
      +
    4. + +
    5. Return value.

    6. +
    +

    StructuredCloneWithTransfer ( input, From eb13657d51f5b3041b004e597d4cd218b612da19 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 7 Mar 2017 20:15:24 -0500 Subject: [PATCH 06/40] OK, I finally replaced StructuredClone --- source | 109 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 34 deletions(-) diff --git a/source b/source index 42b028ef8fb..82af17259ed 100644 --- a/source +++ b/source @@ -8182,7 +8182,10 @@ interface DOMStringList {
  • Let deep be false.

  • -
  • If serialized.[[Type]] is "primitive", then let value be +

  • If serialized.[[Transfer]] is true, then let value be ? + StructuredReceiveTransfer(serialized, targetRealm).

  • + +
  • Otherwise, if serialized.[[Type]] is "primitive", then let value be serialized.[[Value]].

  • Otherwise, if serialized.[[Type]] is "Boolean", then let value be a new Boolean object in @@ -8407,8 +8410,8 @@ interface DOMStringList {

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

      -
    1. Let dataHolder be { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: - value.[[ArrayBufferData]], [[ArrayBufferByteLength]]: +

    2. Let dataHolder be { [[Transfer]]: true, [[Type]]: "ArrayBuffer", + [[ArrayBufferData]]: value.[[ArrayBufferData]], [[ArrayBufferByteLength]]: value.[[ArrayBufferByteLength]] }.

    3. Perform ! DetachArrayBuffer(value).

    4. @@ -8425,7 +8428,8 @@ interface DOMStringList {
    5. Let typeString be the transfer type string for value.

    6. -
    7. Let dataHolder be { [[Type]]: typeString }.

    8. +
    9. Let dataHolder be { [[Transfer]]: true, [[Type]]: typeString + }.

    10. Perform the appropriate transfer steps given value and dataHolder.

    11. @@ -8471,22 +8475,21 @@ interface DOMStringList {
    12. Return value.

    - -

    StructuredCloneWithTransfer ( input, - transferList, targetRealm )

    +

    StructuredSerializeWithTransfer ( value, + transferList )

    1. -

      Let memory be an empty map.

      +

      Let memory be an empty map.

      -

      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.

      +

      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. -

      For each object transferable in transferList: +

      For each transferable of + transferList:

      1. If IsTransferable(transferable) is false, then throw a @@ -8494,46 +8497,84 @@ interface DOMStringList {

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

      3. -
      4. Create an entry in memory with key transferable and value +

      5. Set memory[transferable] to placeholder.

    3. -
    4. Let clone be the result of ? - StructuredClone(input, targetRealm, +

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

    6. -
    7. Let outputTransferList be a new empty List.

    8. +
    9. Let transferDataHolders be a new empty List.

    10. -

      For each object transferable in transferList: +

      For each transferable of + transferList:

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

      2. +
      3. Let placeholder be memory[transferable].

      4. -
      5. Let transferResult be ? Transfer(transferable, - targetRealm).

      6. +
      7. Let transferDataHolder be ? + StructuredTransfer(transferable).

      8. -
      9. -

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

        +
      10. Within serialized, replace all instances of placeholder with + transferDataHolder.

      11. -

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

        - +
      12. Append transferDataHolder to + transferDataHolders.

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

    13. +
    + +

    StructuredDeserializeWithTransfer ( serialized, + transferDataHolders, targetRealm )

    + +
      +
    1. Let memory be an empty map.

    2. + +
    3. Let deserialized be ? StructuredDeserialize(serialized, + targetRealm, memory).

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

    6. + +
    7. +

      For each transferDataHolder of + transferDataHolders:

      -
    8. Add transferResult as the last element of - outputTransferList.

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

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

    11. +
    12. Return { [[Deserialized]]: deserialized, [[TransferredValues]]: + transferredValues }.

    + +

    StructuredCloneWithTransfer ( value, + transferList, targetRealm )

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

    2. + +
    3. Return ? + StructuredDeserializeWithTransfer(serializeResult.[[Serialized]], + serializeResult.[[TransferDataHolders]], targetRealm).

    4. +
    + +

    TODO: update call sites to use [[Deserialized]] and [[TransferredValues]] instead of [[Clone]] + and [[TransferList]].

    +

    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 From 2e2ec4a9e3755e2ebf8f8ff4f5deb0c5aaa7dd92 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 7 Mar 2017 20:35:15 -0500 Subject: [PATCH 07/40] Fix link error --- source | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source b/source index 82af17259ed..2043411d417 100644 --- a/source +++ b/source @@ -8467,8 +8467,8 @@ interface DOMStringList {

  • Let value be a new instance of the platform object type identified by dataHolder.[[Type]].

  • -
  • Perform the appropriate transfer receive steps given dataHolder - and value.

  • +
  • Perform the appropriate transfer-receiving steps given + dataHolder and value.

  • From daab858082664043ba87a2bc413adf86fa8675b8 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 18:16:01 -0500 Subject: [PATCH 08/40] Use IDL [Serializable] and [Transferable] instead of type strings --- source | 105 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 40 deletions(-) diff --git a/source b/source index 2043411d417..d6d3c386181 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
  • @@ -7661,14 +7662,12 @@ interface DOMStringList { serializable objects are necessarily preserved when they are serialized.

    Platform objects can be serializable objects - if they define three things:

    + if they implement only interfaces decorated with the [Serializable] IDL extended attribute. Such + interfaces must also define the following additional algorithms:

    -
    A serialization type string
    -

    A string that uniquely identifies this class of serializable objects, so that - the StructuredSerialize and StructuredDeserialize algorithms can - recognize instances of serialized data to which this definition applies.

    -
    serialization steps, taking a platform object value and a Record serialized
    @@ -7702,8 +7701,13 @@ interface DOMStringList {

    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.

    -

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

    +

    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 @@ -7716,12 +7720,11 @@ interface DOMStringList {

    We could then define Person instances to be serializable - objects by giving the following definitions for them:

    + objects by annotating the Person interface with the [Serializable] extended attribute, and defining the + following accompanying algorithms:

    -
    serialization type string
    -
    "Person"
    -
    serialization steps
      @@ -7751,6 +7754,8 @@ interface DOMStringList {
    +

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

    Transferable objects

    @@ -7765,14 +7770,12 @@ interface DOMStringList { been transferred, it cannot be transferred, or indeed used, again.

    Platform objects can be transferable objects - if they define three things:

    + if they implement only interfaces decorated with the [Transferable] IDL extended attribute. Such + interfaces must also define the following additional algorithms:

    -
    A transfer type string
    -

    A string that uniquely identifies this class of transferable objects, so that - the StructuredTransfer and StructuredReceiveTransfer algorithms - can recognize instances of data to which this definition applies.

    -
    transfer steps, taking a platform object value and a Record dataHolder
    @@ -7804,14 +7807,22 @@ interface DOMStringList {

    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.

    -

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

    +

    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.

    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.

    +

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

    +

    TODO: delete the below

    serializable object:

      -
    1. Let typeString be the serialization type string for +

    2. Let typeString be the identifier of the primary interface of value.

    3. Let serialized be { [[Type]]: typeString }.

    4. @@ -8294,11 +8305,19 @@ interface DOMStringList {

      Otherwise:

        -
      1. Assert: serialized.[[Type]] is a serialization type string for a - platform object.

      2. +
      3. Let interfaceName be serialized.[[Type]].

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

      6. -
      7. Let value be a new instance of the platform object type - identified by serialized.[[Type]].

      8. +
      9. +

        Let value be a new instance of the interface identified by + interfaceName, created in targetRealm.

        + +

        This step can potentially fail if for some reason allocating the object is + impossible, such as low-memory situations.

        +
      10. Set deep to true.

      @@ -8379,12 +8398,9 @@ interface DOMStringList {

      Otherwise:

        -
      1. Assert: serialized.[[Type]] is a serialization type string for - a platform object.

      2. -
      3. -

        Perform the appropriate deserialization steps given serialized - and value.

        +

        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 @@ -8425,14 +8441,14 @@ interface DOMStringList {

      4. Assert: value is a platform object that is a transferable object.

      5. -
      6. Let typeString be the transfer type string for +

      7. Let interfaceName be the identifier of the primary interface of value.

      8. -
      9. Let dataHolder be { [[Transfer]]: true, [[Type]]: typeString +

      10. Let dataHolder be { [[Transfer]]: true, [[Type]]: interfaceName }.

      11. -
      12. Perform the appropriate transfer steps given value and - dataHolder.

      13. +
      14. Perform the appropriate transfer steps for the interface identified by + interfaceName, given value and dataHolder.

      15. Set value.[[Detached]] to true.

      @@ -8461,14 +8477,23 @@ interface DOMStringList {

      Otherwise:

        -
      1. Assert: dataHolder.[[Type]] is a transfer type string for a - platform object.

      2. +
      3. Let interfaceName be dataHolder.[[Type]].

      4. -
      5. Let value be a new instance of the platform object type - identified by dataHolder.[[Type]].

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

      8. + +
      9. +

        Let value be a new instance of the interface identified by + interfaceName, created in targetRealm.

        -
      10. Perform the appropriate transfer-receiving steps given - dataHolder and value.

      11. +

        This step can potentially fail if for some reason allocating the object is + impossible, such as low-memory situations.

        + + +
      12. Perform the appropriate transfer-receiving steps for the interface + identified by interfaceName given dataHolder and + value.

      From 63ef273ce86e892ef5d5e65e8b11921345ffa780 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 18:18:21 -0500 Subject: [PATCH 09/40] Fix nits --- source | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source b/source index d6d3c386181..1e2a0d20b85 100644 --- a/source +++ b/source @@ -7994,7 +7994,7 @@ interface DOMStringList { "DataCloneError" DOMException.

      For instance, a proxy object.

      - +
    5. Otherwise:

      @@ -8152,8 +8152,8 @@ interface DOMStringList {

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

      const o = {};
      
      From 9ae5d5e1b0e505d88ba111f9994c34a8a48497fd Mon Sep 17 00:00:00 2001
      From: Domenic Denicola 
      Date: Wed, 8 Mar 2017 18:23:42 -0500
      Subject: [PATCH 10/40] Don't use "let" to declare variables inside an "if"
       scope
      
      ---
       source | 68 +++++++++++++++++++++++++++++++---------------------------
       1 file changed, 36 insertions(+), 32 deletions(-)
      
      diff --git a/source b/source
      index 1e2a0d20b85..213f97ea00f 100644
      --- a/source
      +++ b/source
      @@ -7857,23 +7857,25 @@ interface DOMStringList {
          
    6. If Type(value) is Symbol, then throw a "DataCloneError" DOMException.

    7. -
    8. If value has a [[BooleanData]] internal slot, then let serialized be +

    9. Let serialized be an uninitialized value.

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

    12. -
    13. Otherwise, if value has a [[NumberData]] internal slot, then let - serialized be { [[Type]]: "Number", [[NumberData]]: value.[[NumberData]] +

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

    15. -
    16. Otherwise, if value has a [[StringData]] internal slot, then let - serialized be { [[Type]]: "String", [[StringData]]: value.[[StringData]] +

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

    18. -
    19. Otherwise, if value has a [[DateValue]] internal slot, then let - serialized be { [[Type]]: "Date", [[DateValue]]: value.[[DateValue]] +

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

    21. -
    22. Otherwise, if value has a [[RegExpMatcher]] internal slot, then let - serialized be { [[Type]]: "RegExp", [[RegExpMatcher]]: +

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

    24. @@ -7884,7 +7886,7 @@ interface DOMStringList {
    25. If IsDetachedBuffer(value) is true, then throw a "DataCloneError" DOMException.

    26. -
    27. Let serialized be { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: +

    28. Set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: value.[[ArrayBufferData]], [[ArrayBufferByteLength]]: value.[[ArrayBufferByteLength]] }.

    @@ -7902,7 +7904,7 @@ interface DOMStringList {
  • Assert: bufferSerialized.[[Type]] is "ArrayBuffer".

  • -
  • If value has a [[DataView]] internal slot, then let serialized be +

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

  • @@ -7913,7 +7915,7 @@ interface DOMStringList {
    1. Assert: value has a [[TypedArrayName]] internal slot.

    2. -
    3. Let serialized be { [[Type]]: "ArrayBufferView", [[Constructor]]: +

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

    5. @@ -7926,7 +7928,7 @@ interface DOMStringList {

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

        -
      1. Let serialized be { [[Type]]: "Map", [[MapData]]: a new empty

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

      2. Set deep to true.

      3. @@ -7937,7 +7939,7 @@ interface DOMStringList {

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

          -
        1. Let serialized be { [[Type]]: "Set", [[SetData]]: a new empty

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

        2. Set deep to true.

        3. @@ -7954,7 +7956,7 @@ interface DOMStringList {
        4. Let inputLen be inputLenDescriptor.[[Value]].

        5. -
        6. Let serialized be { [[Type]]: "Array", [[Length]]: inputLen, +

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

        8. Set deep to true.

        9. @@ -7969,7 +7971,7 @@ interface DOMStringList {
        10. Let typeString be the identifier of the primary interface of value.

        11. -
        12. Let serialized be { [[Type]]: typeString }.

        13. +
        14. Set serialized to { [[Type]]: typeString }.

        15. Set deep to true.

        @@ -8000,7 +8002,7 @@ interface DOMStringList {

        Otherwise:

          -
        1. Let serialized be { [[Type]]: "Object", [[Properties]]: a new empty

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

        2. Set deep to true.

        3. @@ -8193,36 +8195,38 @@ interface DOMStringList {
        4. Let deep be false.

        5. +
        6. Let value be an uninitialized value.

        7. +
        8. If serialized.[[Transfer]] is true, then let value be ? StructuredReceiveTransfer(serialized, targetRealm).

        9. -
        10. Otherwise, if serialized.[[Type]] is "primitive", then let value be +

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

          -
        12. Otherwise, if serialized.[[Type]] is "Boolean", then let value be a new Boolean object in +

        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 let value be a new Number object in +

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

        17. -
        18. Otherwise, if serialized.[[Type]] is "String", then let value be a new String object in +

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

        20. -
        21. Otherwise, if serialized.[[Type]] is "Date", then let value be a new Date object in +

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

        23. -
        24. Otherwise, if serialized.[[Type]] is "RegExp", then let value be a new RegExp object in +

        25. 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]].

        26. -

          Otherwise, if serialized.[[Type]] is "ArrayBuffer", then let value be a new ArrayBuffer +

          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]].

          @@ -8239,13 +8243,13 @@ interface DOMStringList { StructuredDeserialize(input.[[ArrayBufferSerialized]], targetRealm, memory).

        27. -
        28. If input.[[Constructor]] is "DataView", then let value be a new DataView object in +

        29. 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]].

        30. -
        31. Otherwise, let value be a new typed array object, using the constructor given by +

        32. 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 @@ -8259,7 +8263,7 @@ interface DOMStringList {

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

            -
          1. Let value be a new Map object in targetRealm whose [[MapData]] +

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

          3. Set deep to true.

          4. @@ -8270,7 +8274,7 @@ interface DOMStringList {

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

              -
            1. Let value be a new Set object in targetRealm whose [[SetData]] +

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

            3. Set deep to true.

            4. @@ -8284,7 +8288,7 @@ interface DOMStringList {
            5. Let outputProto be the %ArrayPrototype% intrinsic object in targetRealm.

            6. -
            7. Let value be ! ArrayCreate(serialized.[[Length]], +

            8. Set value to ! ArrayCreate(serialized.[[Length]], outputProto).

            9. Set deep to true.

            10. @@ -8295,7 +8299,7 @@ interface DOMStringList {

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

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

              2. +
              3. Set value to a new Object in targetRealm.

              4. Set deep to true.

              @@ -8312,7 +8316,7 @@ interface DOMStringList { DOMException.

            11. -

              Let value be a new instance of the interface identified by +

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

              This step can potentially fail if for some reason allocating the object is @@ -8527,7 +8531,7 @@ interface DOMStringList {

            -
          5. Let serialized be ? StructuredSerialize(input, +

          6. Set serialized to ? StructuredSerialize(input, memory).

          7. Let transferDataHolders be a new empty Date: Wed, 8 Mar 2017 18:37:30 -0500 Subject: [PATCH 11/40] OffscreenCanvas transfer updated --- source | 56 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/source b/source index 213f97ea00f..9b2a6d2429f 100644 --- a/source +++ b/source @@ -65652,6 +65652,7 @@ dictionary ImageEncodeOptions { enum OffscreenRenderingContextType { "2d", "webgl" }; +[Transferable] [Constructor([EnforceRange] unsigned long long width, [EnforceRange] unsigned long long height), Exposed=(Window,Worker)] interface OffscreenCanvas : EventTarget { attribute unsigned long long width; @@ -65747,46 +65748,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. +
            -
          8. Unset this OffscreenCanvas object's bitmap.

          9. +

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

            -
          10. Return new.

          11. +
              +
            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. 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 From 6ab096e372fa5b52339679bd89c50255c536a69f Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 18:49:40 -0500 Subject: [PATCH 12/40] ImageBitmap clone and transfer updated --- source | 69 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/source b/source index 9b2a6d2429f..b76531bfc1e 100644 --- a/source +++ b/source @@ -65652,8 +65652,7 @@ dictionary ImageEncodeOptions { enum OffscreenRenderingContextType { "2d", "webgl" }; -[Transferable] -[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; @@ -93003,7 +93002,7 @@ interface MimeType {

            Images

            -
            [Exposed=(Window,Worker)]
            +  
            [Exposed=(Window,Worker), Serializable, Transferable]
             interface ImageBitmap {
               readonly attribute unsigned long width;
               readonly attribute unsigned long height;
            @@ -93123,46 +93122,64 @@ 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 +

            2. If value's [[Detached]] internal slot is true, then throw a "DataCloneError" DOMException.

            3. -
            4. 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.

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

            7. + +
            8. 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. +
            -
          12. Set this's [[Detached]] internal slot value to true.

          13. +

            Their transfer steps, given value and dataHolder, are:

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

            2. -
            3. Unset this's bitmap +

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

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

            7. +
            -
          14. Return new.

          15. +

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

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

            2. + +
            3. 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:

            From fe559d1dfe800fe1a111ba8b594dcd065a5cc20a Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 19:02:57 -0500 Subject: [PATCH 13/40] Copy ArrayBuffers at serialization time See https://github.com/whatwg/html/issues/936#issuecomment-285209402 --- source | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/source b/source index b76531bfc1e..689984e2818 100644 --- a/source +++ b/source @@ -2901,8 +2901,9 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
          16. The ArrayCreate abstract operation
          17. The Call abstract operation
          18. -
          19. The CloneArrayBuffer abstract operation
          20. The Construct abstract operation
          21. +
          22. The CopyDataBlockBytes abstract operation
          23. +
          24. The CreateByteDataBlock abstract operation
          25. The CreateDataProperty abstract operation
          26. The DetachArrayBuffer abstract operation
          27. The EnqueueJob abstract operation
          28. @@ -7886,9 +7887,20 @@ interface DOMStringList {
          29. If IsDetachedBuffer(value) is true, then throw a "DataCloneError" DOMException.

          30. +
          31. Let size be value.[[ArrayBufferByteLength]].

          32. + +
          33. +

            Let dataCopy be ? CreateByteDataBlock(size).

            + +

            This can throw a RangeError exception upon + allocation failure.

            +
          34. + +
          35. Perform ! CopyDataBlockBytes(dataCopy, 0, + value.[[ArrayBufferData]], 0, size).

          36. +
          37. Set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: - value.[[ArrayBufferData]], [[ArrayBufferByteLength]]: - value.[[ArrayBufferByteLength]] }.

          38. + dataCopy, [[ArrayBufferByteLength]]: size }.

        33. @@ -8664,7 +8676,7 @@ interface DOMStringList {
        34. Let outputArrayBuffer be the %ArrayBuffer% intrinsic object in targetRealm. -

        35. Let output be ? CloneArrayBuffer(input, 0, +

        36. Let output be ? CloneArrayBuffer(input, 0, outputArrayBuffer).

        From f4edf17de979dd014ae42925d32464b9887f91e8 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 19:07:33 -0500 Subject: [PATCH 14/40] Genericize detached-checking That is, for platform objects that are both serializable and transferable, immediately throw for trying to serialize a detached object. ImageBitmap was doing this itself, but this should be generically taken care of for all platform objects. --- source | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source b/source index 689984e2818..5db25b06489 100644 --- a/source +++ b/source @@ -7980,6 +7980,9 @@ interface DOMStringList { data-x="serializable objects">serializable object:

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

        2. +
        3. Let typeString be the identifier of the primary interface of value.

        4. @@ -93143,9 +93146,6 @@ dictionary ImageBitmapOptions { are:

            -
          1. If value'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. From d11aedf23c5963555e445d8eab6ae8d2bc90394d Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 19:33:49 -0500 Subject: [PATCH 15/40] Move MessagePort's [[Transfer]]() to transfer steps --- source | 80 ++++++++++++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 44 deletions(-) diff --git a/source b/source index 5db25b06489..df8734bccfe 100644 --- a/source +++ b/source @@ -8213,7 +8213,7 @@ interface DOMStringList {
          5. Let value be an uninitialized value.

          6. If serialized.[[Transfer]] is true, then let value be ? - StructuredReceiveTransfer(serialized, targetRealm).

          7. + StructuredReceiveTransfer(serialized, targetRealm).

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

            @@ -95950,7 +95950,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();
            @@ -96078,61 +96078,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.)


          From 200cae6ca5463cf797905bc7cb45b70ac94be770 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 19:50:09 -0500 Subject: [PATCH 16/40] Update File API monkeypatch; a few normative fixes - Removes reference to closed blobs - Also serialize the snapshot state --- source | 68 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/source b/source index df8734bccfe..d86fdfd39b6 100644 --- a/source +++ b/source @@ -3182,11 +3182,11 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute spec=FILEAPI>

            -
          • Blob interface
          • -
          • File interface
          • -
          • FileList interface
          • -
          • The concept of a closed Blob
          • -
          • Blob.type
          • +
          • The Blob interface and its + type attribute
          • +
          • The File interface
          • +
          • The FileList interface
          • +
          • The concept of a Blob's snapshot state
          • The concept of read errors
          @@ -9031,37 +9031,55 @@ interface DOMStringList {

          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:

          -

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

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

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

          4. +
          + +

          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:

          +

          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. Let output be a new FileList object in - targetRealm.

          2. +
          3. Set serialized.[[Files]] to an empty list.

          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. For each file in value, append + the sub-serialization of file to + serialized.[[Files]].

          8. +
          -
        5. Return output.

        6. +

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

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

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

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

        8. -
        9. Return a new promise, but continue running these steps in parallel.

        10. From 47fb170ac28218626cc9ad73b4a3d26fb4a8b863 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 19:57:31 -0500 Subject: [PATCH 17/40] Define serialization for File, not just Blob --- source | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/source b/source index d86fdfd39b6..86b72a5ca19 100644 --- a/source +++ b/source @@ -3184,7 +3184,9 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
          • The Blob interface and its type attribute
          • -
          • The File interface
          • +
          • The File interface and its + name and + lastModified attributes
          • The FileList interface
          • The concept of a Blob's snapshot state
          • The concept of read errors
          • @@ -9060,6 +9062,45 @@ interface DOMStringList {
            +

            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. Set serialized.[[SnapshotState]] to value's snapshot + state.

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

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

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

            8. +
            + +

            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 From e65cb80126d86048f011250699aa22e6b2c9b2ee Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 20:04:59 -0500 Subject: [PATCH 18/40] Update ImageData [[Clone]]() -> (de)serialization steps --- source | 49 +++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/source b/source index 86b72a5ca19..e7c477360b8 100644 --- a/source +++ b/source @@ -64536,25 +64536,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 @@ -64657,7 +64638,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 @@ -64687,6 +64668,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 From a861483ed679e95d571009cae37c641cb3cde287 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 20:15:08 -0500 Subject: [PATCH 19/40] Delete most of the old stuff --- source | 387 +++------------------------------------------------------ 1 file changed, 14 insertions(+), 373 deletions(-) diff --git a/source b/source index e7c477360b8..6a7457a1c5c 100644 --- a/source +++ b/source @@ -7623,38 +7623,8 @@ interface DOMStringList {

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

            -

            Cloneable 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.

            - -

            Platform objects have the following internal method:

            - -

            [[Clone]] ( targetRealm, memory )

            - - - -

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

            - -

            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 StructuredClone - abstract operation directly.

            -

            Serializable objects

            -

            TODO: subsume the above section.

            -

            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 @@ -7760,6 +7730,11 @@ interface DOMStringList {

            Objects defined in the JavaScript specification are handled by the StructuredSerialize 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

            Transferable objects support being transferred across [[Transfer]]( targetRealm )

            - -

            StructuredSerialize ( value [ , memory ] )

            @@ -8621,324 +8589,19 @@ interface DOMStringList {

            TODO: update call sites to use [[Deserialized]] and [[TransferredValues]] instead of [[Clone]] and [[TransferList]].

            -

            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 ] )

            + data-dfn-type="abstract-op">StructuredClone ( value, targetRealm + )

      -
    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. If Type(input) is Undefined, Null, Boolean, - String, or Number, then return input.

    6. - -
    7. If Type(input) is Symbol, then throw a - "DataCloneError" DOMException.

    8. - -
    9. Let deepClone be false.

    10. - -
    11. 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.

    12. - -
    13. 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.

    14. - -
    15. 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.

    16. - -
    17. 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.

    18. - -
    19. 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.

    20. - -
    21. -

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

      - -
        -
      1. If IsDetachedBuffer(input) is true, then throw a - "DataCloneError" DOMException.

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

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

      5. -
      -
    22. - -
    23. -

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

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

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

      4. - -
      5. 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.

      6. - -
      7. -

        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. Let output be ? TypedArrayCreate(constructor, - « bufferClone, byteOffset, length »). -

        -
      8. -
      -
    24. - -
    25. -

      Otherwise, if input 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 deepClone to true.

      4. -
      -
    26. - -
    27. -

      Otherwise, if input 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 deepClone to true.

      4. -
      -
    28. - -
    29. -

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

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

      2. - -
      3. Let outputProto be the %ArrayPrototype% intrinsic object in - targetRealm.

      4. - -
      5. Let output be ! ArrayCreate(inputLen, - outputProto).

      6. - -
      7. Set deepClone to true.

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

    32. - -
    33. Otherwise, if IsCallable(input) is true, then throw a - "DataCloneError" DOMException.

    34. - -
    35. -

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

      - -

      For instance, a [[PromiseState]] or [[WeakMapData]] internal slot.

      -
    36. - -
    37. -

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

      - -

      For instance, a proxy object.

      -
    38. - -
    39. -

      Otherwise:

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

      2. - -
      3. Set deepClone to true.

      4. -
      -
    40. - -
    41. Create an entry in memory whose key is input and value is - output.

    42. - -
    43. -

      If deepClone is true, then:

      - -
        -
      1. -

        If input 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,

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

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

          4. -
          - -
        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,

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

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

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

          6. -
          -
        8. -
        -
      2. - -
      3. -

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

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

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

        4. - -
        5. -

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

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

          2. - -
          3. Add outputEntry as the last element of outputList.

          4. -
          -
        6. -
        -
      4. - -
      5. -

        Otherwise: - -

          -
        1. Let enumerableKeys be a new empty List.

        2. - -
        3. -

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

          +
        4. Let serialized be ? + StructuredSerialize(value).

        5. -
            -
          1. -

            If Type(key) is String, then:

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

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

            4. -
            -
          2. -
          - - -
        6. -

          For each key in enumerableKeys:

          - -
            -
          1. -

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

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

            2. - -
            3. Let outputValue be ? - StructuredClone(inputValue, targetRealm, - memory).

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

            6. -
            -
          2. -
          -
        7. -
        - -

        The key collection performed above is very similar to the JavaScript - specification's EnumerableOwnProperties operation, but crucially it uses the - deterministic ordering provided by the [[OwnPropertyKeys]] internal method, instead of - reordering the keys in an unspecified manner as EnumerableOwnProperties does. -

        -
      6. -
      -
    44. - -
    45. Return output.

    46. +
    47. Return ? StructuredDeserialize(serialized, + targetRealm).

    -

    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.

    -

    IsTransferable ( O )

    @@ -8969,34 +8632,12 @@ interface DOMStringList {
  • Return false.

  • -

    Transfer ( input, targetRealm )

    - -
      -
    1. -

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

      - -
        -
      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. Perform ! DetachArrayBuffer(input).

      4. - -
      5. Return output.

      6. -
      -
    2. - -
    3. Return ? input.[[Transfer]](targetRealm).

    4. -
    -

    Performing structured clones from other specifications

    +

    TODO: needs updating

    +

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

    + StructuredCloneWithTransfer, and IsTransferable abstract operations.

    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 From ccdd20446317e39d728a1bfcaf9e8d7acb80f6d2 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 20:41:55 -0500 Subject: [PATCH 20/40] Update "using from other specifications" with some usage guidance --- source | 82 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 14 deletions(-) diff --git a/source b/source index 6a7457a1c5c..00ed4e5bebd 100644 --- a/source +++ b/source @@ -8632,26 +8632,81 @@ interface DOMStringList {

  • Return false.

  • -

    Performing structured clones from other specifications

    +

    Performing serialization and + transferring from other specifications

    -

    TODO: needs updating

    +

    Other specifications may use the abstract operations defined here. The following provides + some guidance on when each abstract operation is typically useful, with examples. Roughly + speaking, the earlier abstract operations in this list are more broadly useful than the later + ones.

    -

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

    +
    +
    StructuredClone
    +
    +

    Cloning a value into a known target JavaScript Realm

    + +

    history.pushState() and history.replaceState() use + StructuredClone as a sort of sanitization step performed on user-supplied data.

    +
    + +
    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.

    +
    + +
    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.

    + +

    Any API for persisting JavaScript values to the filesystem.

    +
    + +
    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.

    +
    + +
    IsTransferable
    +
    StructuredTransfer
    +
    StructuredReceiveTransfer
    +
    +

    These low-level abstract operations are only used when an API needs to manually transfer + individual objects, instead of handling transfers via a transfer list accepted by one of the + previously-discussed abstract operations.

    +
    +

    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.

    +
    +

    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 StructuredClone, + 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 @@ -8664,13 +8719,12 @@ interface DOMStringList { data-x="concept-incumbent-everything">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

    From 7cd160725c5072ae06c20af696d6bedde63b36a5 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 20:47:35 -0500 Subject: [PATCH 21/40] Add missing link --- source | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source b/source index 00ed4e5bebd..6a7273aab2f 100644 --- a/source +++ b/source @@ -8439,7 +8439,7 @@ interface DOMStringList {
  • Perform the appropriate transfer steps for the interface identified by interfaceName, given value and dataHolder.

  • -
  • Set value.[[Detached]] to true.

  • +
  • Set value.[[Detached]] to true.

  • From 76b63d6e8b334fab520257394014b094d7b2f3ad Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 8 Mar 2017 20:58:57 -0500 Subject: [PATCH 22/40] Fix validation error/bad ID --- source | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source b/source index 6a7273aab2f..c488637fc1a 100644 --- a/source +++ b/source @@ -7730,7 +7730,7 @@ interface DOMStringList {

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

    -

    Originally, this specification defined the concept of +

    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.

    From f3c2bbc7903b17cedcd8fc78d7a084bf89fb0198 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 14:24:58 -0400 Subject: [PATCH 23/40] Update for latest code review --- source | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/source b/source index c488637fc1a..435a5d22a01 100644 --- a/source +++ b/source @@ -7929,8 +7929,8 @@ interface DOMStringList {
  • -

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

    +

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

    +
    1. Let inputLenDescriptor be ? @@ -8182,7 +8182,7 @@ interface DOMStringList {

    2. Let value be an uninitialized value.

    3. -
    4. If serialized.[[Transfer]] is true, then let value be ? +

    5. If serialized.[[Transfer]] is true, then set value to ? StructuredReceiveTransfer(serialized, targetRealm).

    6. Otherwise, if serialized.[[Type]] is "primitive", then set value to @@ -8376,8 +8376,10 @@ interface DOMStringList { StructuredDeserialize(entry.[[Value]], targetRealm, memory).

    7. -
    8. Perform ? CreateDataProperty(value, +

    9. Let result be ! CreateDataProperty(value, entry.[[Key]], deserializedValue).

    10. + +
    11. Assert: result is true.

  • @@ -8457,9 +8459,11 @@ interface DOMStringList { dataHolder.[[ArrayBufferData]], and whose [[ArrayBufferByteLength]] internal slot value is dataHolder.[[ArrayBufferByteLength]].

    -

    Unlike the corresponding step in StructuredDeserialize, 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.

    +

    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.

  • From 1dd72afcc9230c2e1e18e0e0ab4f931938718486 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 14:43:02 -0400 Subject: [PATCH 24/40] Fix MessagePort and usage site of StructuredCloneWithTransfer --- source | 87 +++++++++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/source b/source index 435a5d22a01..eef8c06028c 100644 --- a/source +++ b/source @@ -8590,9 +8590,6 @@ interface DOMStringList { serializeResult.[[TransferDataHolders]], targetRealm).

  • -

    TODO: update call sites to use [[Deserialized]] and [[TransferredValues]] instead of [[Clone]] - and [[TransferList]].

    -

    StructuredClone ( value, targetRealm @@ -95411,11 +95408,11 @@ function receiver(e) {
  • Let cloneRecord be StructuredCloneWithTransfer(message, transfer, targetRealm). Rethrow any exceptions.

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

  • +
  • Let messageClone be cloneRecord.[[Deserialized]].

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

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

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

  • @@ -95900,45 +95897,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 serializeRecord 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.

  • @@ -95949,24 +95921,45 @@ 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 event e now finds itself.

      + +

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

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

    6. + +
    7. Let deserializeRecord be + StructuredDeserializeWithTransfer(serializeRecord.[[Serialized]], + serializeRecord.[[TransferDataHolders]], targetRealm). Rethrow any + exceptions.

    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.

  • From 8fba5940122fa7147165476c0b0380827b91799b Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 14:55:38 -0400 Subject: [PATCH 25/40] Make StructuredDeserializeWithTransfer usage a little simpler --- source | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source b/source index eef8c06028c..68ba89f81d2 100644 --- a/source +++ b/source @@ -8550,13 +8550,14 @@ interface DOMStringList {

    StructuredDeserializeWithTransfer ( serialized, - transferDataHolders, targetRealm )

    + data-dfn-type="abstract-op">StructuredDeserializeWithTransfer ( + serializeWithTransferResult, targetRealm )

    1. Let memory be an empty map.

    2. -
    3. Let deserialized be ? StructuredDeserialize(serialized, +

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

    5. Let transferredValues be a new empty DOMStringList {

    6. For each transferDataHolder of - transferDataHolders:

      + serializeWithTransferResult.[[TransferDataHolders]]:

      1. Append @@ -8582,12 +8583,12 @@ interface DOMStringList { transferList, targetRealm )

          -
        1. Let serializeResult be ? +

        2. Let serializeWithTransferResult be ? StructuredSerializeWithTransfer(value, transferList).

        3. Return ? - StructuredDeserializeWithTransfer(serializeResult.[[Serialized]], - serializeResult.[[TransferDataHolders]], targetRealm).

        4. + StructuredDeserializeWithTransfer(serializeWithTransferResult, + targetRealm).

        @@ -95908,7 +95909,7 @@ interface MessagePort : EventTarget { console that the target port was posted to itself, causing the communication channel to be lost.

      2. -
      3. Let serializeRecord be +

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

      5. @@ -95938,9 +95939,8 @@ interface MessagePort : EventTarget { data-x="concept-relevant-realm">relevant Realm.

      6. Let deserializeRecord be - StructuredDeserializeWithTransfer(serializeRecord.[[Serialized]], - serializeRecord.[[TransferDataHolders]], targetRealm). Rethrow any - exceptions.

      7. + StructuredDeserializeWithTransfer(serializeWithTransferResult, + targetRealm). Rethrow any exceptions.

        From b6a1fe7b105c3bd397001b0f8ea0e038536153f9 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 14:58:42 -0400 Subject: [PATCH 26/40] Inline IsTransferable --- source | 41 +++++++---------------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/source b/source index 68ba89f81d2..d98ca201765 100644 --- a/source +++ b/source @@ -8411,8 +8411,6 @@ interface DOMStringList { data-dfn-type="abstract-op">StructuredTransfer ( value )
          -
        1. Assert: IsTransferable(value) is true.

        2. -
        3. If value has an [[ArrayBufferData]] internal slot, then:

          @@ -8510,8 +8508,14 @@ interface DOMStringList { transferList:

            -
          1. If IsTransferable(transferable) is false, then throw a +

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

          3. + +
          4. If O has a [[Detached]] internal slot, and + O.[[Detached]] is true, then throw a "DataCloneError" DOMException.

          5. + false.

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

          7. @@ -8604,36 +8608,6 @@ interface DOMStringList { targetRealm).

          -

          IsTransferable ( O )

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

          2. - -
          3. -

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

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

            2. - -
            3. Return true.

            4. -
            -
          4. - -
          5. -

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

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

            2. - -
            3. Return true.

            4. -
            -
          6. - -
          7. Return false.

          8. -
          -

          Performing serialization and transferring from other specifications

          @@ -8682,7 +8656,6 @@ interface DOMStringList { MessagePort has been shipped.

          -
          IsTransferable
          StructuredTransfer
          StructuredReceiveTransfer
          From c4db1754154ae1e7634693f8f8d11687e683a8a5 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 15:07:12 -0400 Subject: [PATCH 27/40] Inline StructuredTransfer --- source | 95 ++++++++++++++++++++++++++-------------------------------- 1 file changed, 43 insertions(+), 52 deletions(-) diff --git a/source b/source index d98ca201765..87ceaab5635 100644 --- a/source +++ b/source @@ -7762,9 +7762,6 @@ interface DOMStringList { independent of any JavaScript Realm.

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

          - -

          These steps may themselves call StructuredTransfer to transfer nested data - structures.

          transfer-receiving steps, taking a Record @@ -7799,7 +7796,7 @@ interface DOMStringList { platform object has been transferred, it cannot be transferred again.

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

          + StructuredSerializeWithTransfer abstract operation directly.

          StructuredSerialize ( value [ , @@ -8407,45 +8404,6 @@ interface DOMStringList {
        4. Return value.

        -

        StructuredTransfer ( value )

        - -
          -
        1. -

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

          - -
            -
          1. Let dataHolder be { [[Transfer]]: true, [[Type]]: "ArrayBuffer", - [[ArrayBufferData]]: value.[[ArrayBufferData]], [[ArrayBufferByteLength]]: - value.[[ArrayBufferByteLength]] }.

          2. - -
          3. Perform ! DetachArrayBuffer(value).

          4. -
          -
        2. - -
        3. -

          Otherwise:

          - -
            -
          1. Assert: value is a platform object that is a transferable object.

          2. - -
          3. Let interfaceName be the identifier of the primary interface of - value.

          4. - -
          5. Let dataHolder be { [[Transfer]]: true, [[Type]]: interfaceName - }.

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

          8. - -
          9. Set value.[[Detached]] to true.

          10. -
          -
        4. - -
        5. Return dataHolder.

          -
        -

        StructuredReceiveTransfer ( dataHolder, targetRealm )

        @@ -8509,13 +8467,16 @@ interface DOMStringList {
        1. If transferable has an [[ArrayBufferData]] internal slot, and ! - IsDetachedBuffer(O) is true, then throw a + IsDetachedBuffer(transferable) is true, then throw a "DataCloneError" DOMException.

        2. -
        3. If O has a [[Detached]] internal slot, and - O.[[Detached]] is true, then throw a +

        4. If transferable does not have a [[Detached]] internal slot + (i.e., transferable is not a transferable + platform object), then throw a "DataCloneError" + DOMException.

        5. + +
        6. If transferable.[[Detached]] is true, then throw a "DataCloneError" DOMException.

        7. - false.

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

        9. @@ -8537,13 +8498,44 @@ interface DOMStringList {
          1. Let placeholder be memory[transferable].

          2. -
          3. Let transferDataHolder be ? - StructuredTransfer(transferable).

          4. +
          5. Let dataHolder be an uninitialized value.

          6. + +
          7. +

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

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

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

            4. +
            +
          8. + +
          9. +

            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 { [[Transfer]]: true, [[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. +
            +
          10. Within serialized, replace all instances of placeholder with - transferDataHolder.

          11. + dataHolder.

            -
          12. Append transferDataHolder to +

          13. Append dataHolder to transferDataHolders.

          @@ -8656,7 +8648,6 @@ interface DOMStringList { MessagePort has been shipped.

          -
          StructuredTransfer
          StructuredReceiveTransfer

          These low-level abstract operations are only used when an API needs to manually transfer From 24d8dd10356bc991073a4002e33d060db3501590 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 15:15:13 -0400 Subject: [PATCH 28/40] Inline StructuredReceiveTransfer; remove out of place note about allocation failure --- source | 108 +++++++++++++++++++++++---------------------------------- 1 file changed, 44 insertions(+), 64 deletions(-) diff --git a/source b/source index 87ceaab5635..c0a8066bddc 100644 --- a/source +++ b/source @@ -7773,9 +7773,6 @@ interface DOMStringList { that up is the job of these steps.

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

          - -

          These steps may themselves call StructuredReceiveTransfer to receive the - transfer of nested data structures.

    @@ -8179,8 +8176,48 @@ interface DOMStringList {
  • Let value be an uninitialized value.

  • -
  • If serialized.[[Transfer]] is true, then set value to ? - StructuredReceiveTransfer(serialized, targetRealm).

  • +
  • +

    If serialized.[[Transfer]] is true, then:

    + +
      +
    1. +

      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.

      +
    2. + +
    3. +

      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.

        + +

        This step can potentially fail if for some reason allocating the object is + impossible, such as low-memory situations.

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

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

    @@ -8297,13 +8334,8 @@ interface DOMStringList { targetRealm, then throw a "DataCloneError" DOMException.

  • -
  • -

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

    - -

    This step can potentially fail if for some reason allocating the object is - impossible, such as low-memory situations.

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

  • Set deep to true.

  • @@ -8404,51 +8436,6 @@ interface DOMStringList {
  • Return value.

  • -

    StructuredReceiveTransfer ( dataHolder, - targetRealm )

    - -
      -
    1. -

      If dataHolder.[[Type]] is "ArrayBuffer", then let value be a new - ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is - dataHolder.[[ArrayBufferData]], and whose [[ArrayBufferByteLength]] internal slot - value is dataHolder.[[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.

      -
    2. - -
    3. -

      Otherwise:

      - -
        -
      1. Let interfaceName be dataHolder.[[Type]].

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

      4. - -
      5. -

        Let value be a new instance of the interface identified by - interfaceName, created in targetRealm.

        - -

        This step can potentially fail if for some reason allocating the object is - impossible, such as low-memory situations.

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

      8. -
      -
    4. - -
    5. Return value.

    6. -
    -

    StructuredSerializeWithTransfer ( value, transferList )

    @@ -8647,13 +8634,6 @@ interface DOMStringList { uses this pair of abstract operations, as the destination Realm is not known until the MessagePort has been shipped.

    - -
    StructuredReceiveTransfer
    -
    -

    These low-level abstract operations are only used when an API needs to manually transfer - individual objects, instead of handling transfers via a transfer list accepted by one of the - previously-discussed abstract operations.

    -

    In general, call sites may pass in Web IDL values instead of JavaScript values; this is to be From 66c146a395661f49b1be0a006df70adf20ec5142 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 15:34:05 -0400 Subject: [PATCH 29/40] Minor tweaks, mostly to notes around _memory_ --- source | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/source b/source index c0a8066bddc..e6156af4f1c 100644 --- a/source +++ b/source @@ -7808,8 +7808,13 @@ interface DOMStringList { objects.

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

    2. +
    3. +

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

      + +

      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.

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

    5. @@ -8138,7 +8143,7 @@ interface DOMStringList { StructuredSerialize:

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

      it produces the following result:

      @@ -8166,8 +8171,13 @@ interface DOMStringList { objects (especially ArrayBuffer objects).

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

      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. If memory[serialized] exists, then return memory[serialized].

      5. @@ -8203,13 +8213,8 @@ interface DOMStringList { targetRealm, then throw a "DataCloneError" DOMException.

        -
      6. -

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

        - -

        This step can potentially fail if for some reason allocating the object is - impossible, such as low-memory situations.

        -
      7. +
      8. Set value to a new instance of the interface identified by + interfaceName, created in targetRealm.

      9. Perform the appropriate transfer-receiving steps for the interface identified by interfaceName given serialized and @@ -8444,8 +8449,9 @@ interface DOMStringList {

      10. Let memory be an empty map.

        -

        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.

        +

        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.

      11. @@ -8537,7 +8543,13 @@ interface DOMStringList { serializeWithTransferResult, targetRealm )
          -
        1. Let memory be an empty map.

        2. +
        3. +

          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.

          +
        4. Let deserialized be ? StructuredDeserialize(serializeWithTransferResult.[[Serialized]], From 1a726a2c2d34e8a6d40cc6e4caf029d27168286a Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 15:56:48 -0400 Subject: [PATCH 30/40] Update history.state to use serialize/deserialize --- source | 104 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/source b/source index e6156af4f1c..b70aa84d032 100644 --- a/source +++ b/source @@ -8612,9 +8612,10 @@ o.myself = o;

          Cloning a value into a known target JavaScript Realm

          -

          history.pushState() and history.replaceState() use - StructuredClone as a sort of sanitization step performed on user-supplied data.

          +

          broadcastChannel.postMessage() uses + StructuredClone to create new cloned values for each destination being broadcast + to.

          StructuredCloneWithTransfer
          @@ -8632,7 +8633,16 @@ o.myself = o;

          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.

          -

          Any API for persisting JavaScript values to the filesystem.

          +

          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.

          + +

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

          StructuredSerializeWithTransfer
          @@ -80315,9 +80325,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 @@ -80331,8 +80342,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.


          @@ -80351,22 +80362,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 @@ -80387,8 +80402,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.

          @@ -80416,8 +80430,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.

          @@ -80488,7 +80502,7 @@ interface History {
          -

          Returns the current state object.

          +

          Returns the current serialied state, deserialized into an object.

          @@ -80740,8 +80754,8 @@ interface History {
        5. Let targetRealm be this History object's relevant Realm.

        6. -
        7. Let cloned data be StructuredClone(data, - targetRealm). Rethrow any exceptions.

        8. +
        9. Let serializedData be StructuredSerialize(data). + Rethrow any exceptions.

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

        11. -
        12. 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.

        13. +
        14. 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.

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

        16. @@ -80820,8 +80834,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.

          @@ -80842,13 +80858,8 @@ interface History { -
        17. - -

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

          - -
        18. +
        19. Set history.state to + StructuredDeserialize(serializedData, targetRealm).

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

        21. @@ -83349,9 +83360,12 @@ State: <OUTPUT NAME=I>1</OUTPUT> <INPUT VALUE="Increment" TYPE=BUTTON O
        22. Let targetRealm be the current Realm Record.

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

        25. +
        26. 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.

        27. + +
        28. Otherwise, let state be null.

        29. Set history.state to state.

        30. From bbaa65bbd994c110893d270b23779198144c4179 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 16:08:26 -0400 Subject: [PATCH 31/40] Update BroadcastChannel to use serialize/deserialize --- source | 87 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/source b/source index b70aa84d032..7209b97c0f2 100644 --- a/source +++ b/source @@ -8603,21 +8603,9 @@ o.myself = o; 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. Roughly - speaking, the earlier abstract operations in this list are more broadly useful than the later - ones.

          + some guidance on when each abstract operation is typically useful, with examples.

          -
          StructuredClone
          -
          -

          Cloning a value into a known target JavaScript Realm

          - -

          broadcastChannel.postMessage() uses - StructuredClone to create new cloned values for each destination being broadcast - to.

          -
          -
          StructuredCloneWithTransfer

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

          @@ -8627,11 +8615,29 @@ o.myself = o; 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.

          +
          + +
          StructuredClone
          +
          +

          Cloning a value into a known target JavaScript Realm

          +
          +
          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.

          + saved for an indefinite amount of time, and then reified back into a JavaScript value later, + possibly multiple times.

          history.pushState() and history.replaceState() use @@ -8641,21 +8647,15 @@ o.myself = o; data-x="dom-history-state">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.

          - -
          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.

          -

          In general, call sites may pass in Web IDL values instead of JavaScript values; this is to be @@ -80858,8 +80858,11 @@ interface History { -

        31. Set history.state to - StructuredDeserialize(serializedData, targetRealm).

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

        34. + +
        35. Set history.state to state.

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

        37. @@ -95910,9 +95913,9 @@ interface MessagePort : EventTarget {
        38. Let deserializeRecord be StructuredDeserializeWithTransfer(serializeWithTransferResult, - targetRealm). Rethrow any exceptions.

        39. - + targetRealm).

          +
        40. Let messageClone be deserializeRecord.[[Deserialized]].

        41. @@ -96165,8 +96168,8 @@ interface BroadcastChannel : EventTarget {
        42. Let targetRealm be a user-agent defined Realm.

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

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

        47. Let destinations be a list of BroadcastChannel objects that @@ -96214,18 +96217,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.

          From 60ecdf8c02e73bf9e87ff4455487f419cf5e030d Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 16:14:10 -0400 Subject: [PATCH 32/40] Add explicit asserts that you can't deserialize a transfer twice --- source | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source b/source index 7209b97c0f2..e39e6675396 100644 --- a/source +++ b/source @@ -8187,9 +8187,15 @@ o.myself = o;
        48. Let value be an uninitialized value.

        49. -

          If serialized.[[Transfer]] is true, then:

          +

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

            +
          1. 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.)

          2. + +
          3. Set serialized.[[TransferConsumed]] to true.

          4. +
          5. If serialized.[[Type]] is "ArrayBuffer", then set value to a new ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is @@ -8497,7 +8503,7 @@ o.myself = o;

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

              -
            1. Set dataHolder to { [[Transfer]]: true, [[Type]]: "ArrayBuffer", +

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

            3. @@ -8515,8 +8521,8 @@ o.myself = o;
            4. Let interfaceName be the identifier of the primary interface of transferable.

            5. -
            6. Set dataHolder to { [[Transfer]]: true, [[Type]]: interfaceName - }.

            7. +
            8. Set dataHolder to { [[TransferConsumed]]: false, [[Type]]: + interfaceName }.

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

            10. From 84f4ddcf1344cc376737e9b245c81bb1caf61de9 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 14 Mar 2017 16:27:03 -0400 Subject: [PATCH 33/40] Fix link error I wonder why these aren't being caught locally for me... --- source | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source b/source index e39e6675396..c85e8eecbf5 100644 --- a/source +++ b/source @@ -80508,7 +80508,7 @@ interface History {
              -

              Returns the current serialied state, deserialized into an object.

              +

              Returns the current serialized state, deserialized into an object.

              From 4e8bea00db8f1464124d7d983eb078cb86cb4fce Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 15 Mar 2017 17:48:42 -0400 Subject: [PATCH 34/40] Remove StructuredClone --- source | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/source b/source index c85e8eecbf5..61348440347 100644 --- a/source +++ b/source @@ -8592,19 +8592,6 @@ o.myself = o; targetRealm).

            - -

            StructuredClone ( value, targetRealm - )

            - -
              -
            1. Let serialized be ? - StructuredSerialize(value).

            2. - -
            3. Return ? StructuredDeserialize(serialized, - targetRealm).

            4. -
            -

            Performing serialization and transferring from other specifications

            @@ -8633,11 +8620,6 @@ o.myself = o; MessagePort has been shipped.

            -
            StructuredClone
            -
            -

            Cloning a value into a known target JavaScript Realm

            -
            -
            StructuredSerialize
            StructuredDeserialize
            @@ -8668,16 +8650,21 @@ o.myself = o; 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 StructuredClone, - 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 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.

            window.postMessage() performs @@ -8688,7 +8675,7 @@ o.myself = o;

            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.

            From 3b89876eb35ae261ef9fbe9d1d55e1356553ad17 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 15 Mar 2017 17:56:15 -0400 Subject: [PATCH 35/40] Fix IsTransferable inlining --- source | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source b/source index 61348440347..1b8ea4d6c74 100644 --- a/source +++ b/source @@ -8465,16 +8465,16 @@ o.myself = o; transferList:

              -
            1. If transferable has an [[ArrayBufferData]] internal slot, and ! - IsDetachedBuffer(transferable) is true, then throw a +

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

            3. -
            4. If transferable does not have a [[Detached]] internal slot - (i.e., transferable is not a transferable - platform object), then throw a "DataCloneError" - DOMException.

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

            7. -
            8. If transferable.[[Detached]] is true, then throw a +

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

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

            11. From e3edc1dbb0908aeaf204a3550dd83c69fb8c7001 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 15 Mar 2017 17:58:33 -0400 Subject: [PATCH 36/40] Fix portMessage event vs. task reference --- source | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source b/source index 1b8ea4d6c74..80b6b92bf26 100644 --- a/source +++ b/source @@ -95895,10 +95895,10 @@ interface MessagePort : EventTarget {
              1. Let finalTargetPort be the MessagePort in whose port message - queue the event e now finds itself.

                + queue the task now finds itself.

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

                + itself was transferred and thus all its tasks moved along with it.

              2. Let targetRealm be finalTargetPort's Date: Wed, 15 Mar 2017 17:59:27 -0400 Subject: [PATCH 37/40] Fix URL StructuredSerialize reference --- source | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source b/source index 80b6b92bf26..ae7f1a3ee8a 100644 --- a/source +++ b/source @@ -22314,8 +22314,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 From 0be172fe9be8371cefab16e59fbe7db69094c056 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 15 Mar 2017 18:10:16 -0400 Subject: [PATCH 38/40] Remove redundant word --- source | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source b/source index ae7f1a3ee8a..dd167d343fb 100644 --- a/source +++ b/source @@ -7638,7 +7638,7 @@ interface DOMStringList { if they implement only interfaces decorated with the [Serializable] IDL extended attribute. Such - interfaces must also define the following additional algorithms:

                + interfaces must also define the following algorithms:

                serialization steps, taking a platform object @@ -7751,7 +7751,7 @@ interface DOMStringList { if they implement only interfaces decorated with the [Transferable] IDL extended attribute. Such - interfaces must also define the following additional algorithms:

                + interfaces must also define the following algorithms:

                transfer steps, taking a platform object From 070631b0cb4117c75607ffc38d7cdaedee53859a Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 16 Mar 2017 14:42:23 -0400 Subject: [PATCH 39/40] Fix nits found --- source | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source b/source index dd167d343fb..8b81433db51 100644 --- a/source +++ b/source @@ -8484,7 +8484,7 @@ o.myself = o;
              -
            12. Set serialized to ? StructuredSerialize(input, +

            13. Let serialized be ? StructuredSerialize(input, memory).

            14. Let transferDataHolders be a new empty CanvasDrawImage { void drawImage(CanvasImageSource image, unrestricted double sx, unrestricted double sy, unrestricted double sw, unrestricted double sh, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh); }; -[NoInterfaceObject, Exposed=(Window,Worker)] +[NoInterfaceObject, Exposed=(Window,Worker), Serializable] interface CanvasImageData { // pixel manipulation ImageData createImageData(double sw, double sh); From 02c5ca461519f1b788e8558a050c5caaa05f727b Mon Sep 17 00:00:00 2001 From: Anne van Kesteren Date: Fri, 17 Mar 2017 06:47:32 +0100 Subject: [PATCH 40/40] Move Serializable annotation to the correct interface --- source | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source b/source index 8b81433db51..c1c7b0e1ca5 100644 --- a/source +++ b/source @@ -60146,7 +60146,7 @@ interface CanvasDrawImage { void drawImage(CanvasImageSource image, unrestricted double sx, unrestricted double sy, unrestricted double sw, unrestricted double sh, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh); }; -[NoInterfaceObject, Exposed=(Window,Worker), Serializable] +[NoInterfaceObject, Exposed=(Window,Worker)] interface CanvasImageData { // pixel manipulation ImageData createImageData(double sw, double sh); @@ -60232,7 +60232,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;