2.7. 有構造~dataの安全な渡し方

この節では、~JS仕様による,各種用語と表記規約を利用する。 `JAVASCRIPT$r ◎ This section uses the terminology and typographic conventions from the JavaScript specification. [JAVASCRIPT]

【 加えて、この訳では次のような略記法を導入する: 】

2.7.1. 直列化-可能な~obj

`直列化-可能$な~objは、所与の`~Realm$が何であれ,それに独立な仕方で直列化され, 後に逆直列化されることを~supportする 【逆直列化( deserialize ) — 字義通り,直列化された結果から元に復元すること】 。 これにより、それを~diskに格納して後に復旧したり,文書や~workerの境界を(異なる`生成元$や異なる`~event-loop$に属する文書~間も含めて)越えて~cloneすることも許容される。 ◎ 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).

~objには`直列化-可能$でないものもあり、`直列化-可能$なものでも,そのすべての側面が直列化-時に保全されるとは限らない。 ◎ Not all objects are serializable objects, and not all aspects of objects that are serializable objects are necessarily preserved when they are serialized.

`~platform~obj$は、 `Serializable@xA ~IDL`拡張属性$が付与された~interfaceのみを実装するならば、`直列化-可能$である。 そのような~interfaceは、次の~algoも定義し~MUST(括弧内は入力): ◎ Platform objects can be serializable objects if they implement only interfaces decorated with the [Serializable] IDL extended attribute. Such interfaces must also define the following algorithms:

`直列化~手続き@( `~platform~obj$ %値, `Record$js %直列形, ~boolean %蓄積用 ) ◎ serialization steps, taking a platform object value, a Record serialized, and a boolean forStorage
%値 内の~dataを %直列形 の各~fieldの中に直列化するための手続き。 %直列形 の中に直列化される結果の~dataは、どの`~Realm$からも独立で~MUST。 ◎ A set of steps that serializes the data in value into fields of serialized. The resulting data serialized into serialized must be independent of any JavaScript Realm.
この手続きは、直列化が可能でない場合は,例外を投出してもよい/し得る。 ◎ These steps may throw an exception if serialization is not possible.
この手続きは、`下位直列化$を遂行して,入子の~data構造を直列化してもよい/し得る。 それらは `StructuredSerialize$jA を直に~callするべきでない — そうすると、重要な %memory 引数が省略されることになるので。 ◎ 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.
この手続きを導入するときは、~algoに関連する場合を除き, %蓄積用 引数は省略するべきである。 ◎ The introduction of these steps should omit mention of the forStorage argument if it is not relevant to the algorithm.
`逆直列化~手続き@( `Record$js %直列形, `~platform~obj$ %値 ) ◎ deserialization steps, taking a Record serialized and a platform object value
%値 を適切に設定しておくために, %直列形 内の~dataを逆直列化するための手続き。 %値 は,新たな[ 当の`~platform~obj$の型の~instance ]であり、その内部~dataは何も設定されてないものになる — それを設定しておくのが、この手続きの仕事である。 ◎ A set of steps that deserializes the data in serialized, using it to set up value as appropriate. value will be a newly-created instance of the platform object type in question, with none of its internal data set up; setting that up is the job of these steps.
この手続きは、逆直列化が可能でない場合は,例外を投出してもよい/し得る。 ◎ These steps may throw an exception if deserialization is not possible.
この手続きは、`下位逆直列化$を遂行して,入子の~data構造を逆直列化してもよい/し得る。 そこでは `StructuredDeserialize$jA を直に~callするべきでない — そうすると、重要な[ %宛先~Realm, %memory ]引数が省略されることになるので。 ◎ These steps may perform a sub-deserialization to deserialize nested data structures. They should not call StructuredDeserialize directly, as doing so will omit the important targetRealm and memory arguments.

これらの手続きにより どの~dataを[ 直列化-/逆直列化- ]するかを決定するのは、個々の~platform~objの定義に委ねられる。 この 2 つの手続きは、概して対称になる。 ◎ 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.

`Serializable$xA 拡張属性は:

  • 引数をとっては~MUST_NOT。
  • ~interface以外に現れては~MUST_NOT。
  • ~interfaceに現れるのは一度限りで~MUST。
  • ~callback~interface上に利用されては~MUST_NOT。
  • [ `部分的~interface$ / `~interface~mixin$ ]上に現れる場合、[ その元の~interface / それを`内包している~interface$ ]にも現れ~MUST — 前者~用に給された[ `直列化~手続き$や`逆直列化~手続き$ ]があれば、それらは後者に付加されているものと解されるべきである。
◎ 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.

ある~platform~obj `Person^I を定義していて,それには次の 2 つの~data片が結付けられているとする: ◎ Let's say we were defining a platform object Person, which had associated with it two pieces of associated data:

  • `~name^i :文字列を値にとる ◎ a name value, which is a string;
  • `~BestFriend^i:別の `Person^c ~instanceまたは ~NULL を値にとる ◎ and a best friend value, which is either another Person instance or null

このとき, `Person^I ~instanceを`直列化-可能$になるように定義するためには、 `Person^I ~interfaceに `Serializable$xA `拡張属性$を注釈して,付帯する~algoを次のように定義する: ◎ We could then define Person instances to be serializable objects by annotating the Person interface with the [Serializable] extended attribute, and defining the following accompanying algorithms:

`直列化~手続き$ ◎ serialization steps
  1. %直列形 . `Name^sl ~SET %値 の `~name^i 値 ◎ Set serialized.[[Name]] to value's associated name value.
  2. %直列形の~BestFriend ~LET %値 の `~BestFriend^i 値の`下位直列化$ ◎ Let serializedBestFriend be the sub-serialization of value's associated best friend value.
  3. %直列形 . `BestFriend^sl ~SET %直列形の~BestFriend ◎ Set serialized.[[BestFriend]] to serializedBestFriend.
`逆直列化~手続き$ ◎ deserialization steps
  1. %値 の `~name^i 値 ~SET %直列形 . `Name^sl ◎ Set value's associated name value to serialized.[[Name]].
  2. %逆直列形の~BestFriend ~LET %直列形 . `BestFriend^sl の`下位逆直列化$ ◎ Let deserializedBestFriend be the sub-deserialization of serialized.[[BestFriend]].
  3. %値 の `~BestFriend^i ~SET %逆直列形の~BestFriend ◎ Set value's associated best friend value to deserializedBestFriend.

~JS仕様にて定義される各種~objは、`StructuredSerialize$jA 抽象演算により直に取扱われる。 ◎ Objects defined in the JavaScript specification are handled by the StructuredSerialize abstract operation directly.

注記: 元々,この仕様は、ある`~Realm$から別へ~cloneすることもできる “~clone可能な~obj” の概念を定義していた。 しかしながら,ある種のより複雑な状況~下での挙動をより良く指定するため、直列化と逆直列化を明示的に与えるよう,この~modelは更新された。 ◎ 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.

2.7.2. 転送-可能な~obj

`転送-可能$な~objは、`~event-loop$間をまたぐ転送を~supportする。 ~obj %O の転送は、実質的に, %O と同じ下層の~dataを参照するような~objを作成し直す一方で,転送-側から %O を切離すことである。 これは、高価な資源の所有権を転送するときに,有用になる。 ~objには`転送-可能$でないものもあり、`転送-可能$なものでも そのすべての側面が転送-時に保全されるとは限らない。 ◎ Transferable objects support being transferred across event loops. Transferring is effectively recreating the object while sharing a reference to the underlying data and then detaching the object being transferred. This is useful to transfer ownership of expensive resources. Not all objects are transferable objects and not all aspects of objects that are transferable objects are necessarily preserved when transferred.

注記: 転送は、不可逆であり,冪等でない演算である。 ~objを転送した側は、それを再び 転送する/利用することはできなくなる。 ◎ Transferring is an irreversible and non-idempotent operation. Once an object has been transferred, it cannot be transferred, or indeed used, again.

`~platform~obj$は、 `Transferable@xA ~IDL`拡張属性$が付与された~interfaceのみを実装するならば、`転送-可能$である。 そのような~interfaceは,次の~algoも定義し~MUST(括弧内は入力): ◎ Platform objects can be transferable objects if they implement only interfaces decorated with the [Transferable] IDL extended attribute. Such interfaces must also define the following algorithms:

`転送-手続き@( `~platform~obj$ %値, `Record$js %~data保持体 ) ◎ transfer steps, taking a platform object value and a Record dataHolder
%値 内の~dataを %~data保持体 の各~fieldの中に転送するための手続き。 %~data保持体 内に保持される結果の~dataは、どの`~Realm$からも独立で~MUST。 ◎ A set of steps that transfers the data in value 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.
`転送-受信-時の手続き@( `Record$js %~data保持体, `~platform~obj$ %値 ) ◎ transfer-receiving steps, taking a Record dataHolder and a platform object value
%~data保持体 内の~dataを受信するための手続き。 %値 は,新たな[ 当の`~platform~obj$の型の~instance ]であり、その内部~dataは何も設定されてないものになる — それを設定しておくのが、この手続きの仕事である。 ◎ 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.

これらの手続きにより どの~dataを転送するか決定するのは、個々の~platform~objの定義に委ねられる。 この 2 つの手続きは、概して対称になる。 ◎ 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.

`Transferable$xA 拡張属性は:

  • 引数をとっては~MUST_NOT。
  • ~interface以外に現れては~MUST_NOT。
  • ~interfaceに現れるのは一度限りで~MUST。
  • ~callback~interface上に利用されては~MUST_NOT。
  • [ `部分的~interface$ / `~interface~mixin$ ]上に現れる場合、[ その元の~interface / それを`内包している~interface$ ]にも現れ~MUST — 前者~用に給された[ `直列化~手続き$や`逆直列化~手続き$ ]があれば、それらは後者に付加されているものと解されるべきである。
◎ 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~obj$のうち,`転送-可能$なものは、 `Detached@sl 内部~slotを持つ。 これは、[ 転送された~platform~objは,再度~転送され得ない ]ことを確保するために利用される。 ◎ 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.

~JS仕様にて定義される各種~objは、 `StructuredSerializeWithTransfer$jA 抽象演算により直に取扱われる。 ◎ Objects defined in the JavaScript specification are handled by the StructuredSerializeWithTransfer abstract operation directly.

2.7.3. `StructuredSerializeInternal^jA ( %値, %蓄積用 [ , %memory ] )

`StructuredSerializeInternal$jA 抽象演算は、~JS値( %値 )を入力にとり,それを`~Realm$から独立な形に直列化する — ここでは `Record$js として表現される。 この直列化された形は、後に異なる~Realm内で新たな~JS値に逆直列化するときに必要とされるすべての情報を持つ。 ◎ The StructuredSerializeInternal abstract operation takes as input a JavaScript value value and serializes it to a Realm-independent form, represented here as a Record. This serialized form has all the information necessary to later deserialize into a new JavaScript value in a different Realm.

この処理-は、例外を投出し得る — 例えば、`直列化-可能$でない~objを直列化しようと試行したとき。 ◎ This process can throw an exception, for example when trying to serialize un-serializable objects.

  1. ~IF[ %memory は給されてない ] ⇒ %memory ~LET 空`~map$ ◎ If memory was not supplied, let memory be an empty map.

    注記: %memory ~mapの目的は、~objが重ねて直列化されるのを避けることにある。 これには、循環参照を保全して,~graphにおける~objの重複を識別することが必要になる。 ◎ 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. ~IF[ %memory[ %値 ] ~NEQ ε ] ⇒ ~RET %memory[ %値 ] ◎ If memory[value] exists, then return memory[value].
  3. %deep ~LET ~F ◎ Let deep be false.
  4. ~IF[ `Type$jA( %値 ) ~IN { `Undefined^jC, `Null^jC, `Boolean^jC, `Number^jC, `BigInt^jC, `String^jC } ] ⇒ ~RET { `Type^sl: `primitive^l, `Value^sl: %値 } ◎終 `JSBIGINT$r ◎ If Type(value) is Undefined, Null, Boolean, Number, BigInt, or String, then return { [[Type]]: "primitive", [[Value]]: value }. [JSBIGINT]
  5. ~IF[ `Type$jA( %値 ) ~EQ `Symbol^jC ] ⇒ ~THROW `DataCloneError$E ◎ If Type(value) is Symbol, then throw a "DataCloneError" DOMException.
  6. %直列形 ~LET ε ◎ Let serialized be an uninitialized value.
  7. ~IF[ %値 . `BooleanData^sl ~NEQ ε ] ⇒ %直列形 ~SET { `Type^sl: `Boolean^l, `BooleanData^sl: %値 . `BooleanData^sl } ◎ If value has a [[BooleanData]] internal slot, then set serialized to { [[Type]]: "Boolean", [[BooleanData]]: value.[[BooleanData]] }.
  8. ~ELIF[ %値 . `NumberData^sl ~NEQ ε ] ⇒ %直列形 ~SET { `Type^sl: `Number^l, `NumberData^sl: %値 . `NumberData^sl } ◎ Otherwise, if value has a [[NumberData]] internal slot, then set serialized to { [[Type]]: "Number", [[NumberData]]: value.[[NumberData]] }.
  9. ~ELIF[ %値 . `BigIntData^sl ~NEQ ε ] ⇒ %直列形 ~SET { `Type^sl: `BigInt^l, `BigIntData^sl: %値 . `BigIntData^sl } ◎終 `JSBIGINT$r ◎ Otherwise, if value has a [[BigIntData]] internal slot, then set serialized to { [[Type]]: "BigInt", [[BigIntData]]: value.[[BigIntData]] }. [JSBIGINT]
  10. ~ELIF[ %値 . `StringData^sl ~NEQ ε ] ⇒ %直列形 ~SET { `Type^sl: `String^l, `StringData^sl: %値 . `StringData^sl } ◎ Otherwise, if value has a [[StringData]] internal slot, then set serialized to { [[Type]]: "String", [[StringData]]: value.[[StringData]] }.
  11. ~ELIF[ %値 . `DateValue^sl ~NEQ ε ] ⇒ %直列形 ~SET { `Type^sl: `Date^l, `DateValue^sl: %値 . `DateValue^sl } ◎ Otherwise, if value has a [[DateValue]] internal slot, then set serialized to { [[Type]]: "Date", [[DateValue]]: value.[[DateValue]] }.
  12. ~ELIF[ %値 . `RegExpMatcher^sl ~NEQ ε ] ⇒ %直列形 ~SET { `Type^sl: `RegExp^l, `RegExpMatcher^sl: %値 . `RegExpMatcher^sl, `OriginalSource^sl: %値 . `OriginalSource^sl, `OriginalFlags^sl: %値 . `OriginalFlags^sl } ◎ Otherwise, if value has a [[RegExpMatcher]] internal slot, then set serialized to { [[Type]]: "RegExp", [[RegExpMatcher]]: value.[[RegExpMatcher]], [[OriginalSource]]: value.[[OriginalSource]], [[OriginalFlags]]: value.[[OriginalFlags]] }.
  13. ~ELIF[ %値 . `ArrayBufferData^sl ~NEQ ε ]: ◎ Otherwise, if value has an [[ArrayBufferData]] internal slot, then:

    1. %~size ~LET %値 . `ArrayBufferByteLength^sl ◎ Let size be value.[[ArrayBufferByteLength]].
    2. ~IF[ ! `IsSharedArrayBuffer$jA( %値 ) ~EQ ~T ]: ◎ If ! IsSharedArrayBuffer(value) is true, then:

      1. ~IF[ %蓄積用 ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If forStorage is true, then throw a "DataCloneError" DOMException.
      2. %直列形 ~SET { `Type^sl: `SharedArrayBuffer^l, `ArrayBufferData^sl: %値 . `ArrayBufferData^sl, `ArrayBufferByteLength^sl: %~size, `AgentCluster^sl: `現在の~Realm~Record$に対応する`~agent-cluster$ } ◎ Set serialized to { [[Type]]: "SharedArrayBuffer", [[ArrayBufferData]]: value.[[ArrayBufferData]], [[ArrayBufferByteLength]]: size, [[AgentCluster]]: the current Realm Record's corresponding agent cluster }.
    3. ~ELSE: ◎ Otherwise:

      1. ~IF[ ! `IsDetachedBuffer$jA( %値 ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If ! IsDetachedBuffer(value) is true, then throw a "DataCloneError" DOMException.
      2. %~dataの複製 ~LET ? `CreateByteDataBlock$jA( %~size ) ◎ Let dataCopy be ? CreateByteDataBlock(size).

        注記: これは、割当ての失敗に際しては `RangeError$E 例外を投出し得る ◎ This can throw a RangeError exception upon allocation failure.

      3. ! `CopyDataBlockBytes$jA( %~dataの複製, 0, %値 . `ArrayBufferData^sl, 0, %~size ) を遂行する ◎ Perform ! CopyDataBlockBytes(dataCopy, 0, value.[[ArrayBufferData]], 0, size).
      4. %直列形 ~SET { `Type^sl: `ArrayBuffer^l, `ArrayBufferData^sl: %~dataの複製, `ArrayBufferByteLength^sl: %~size } ◎ Set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size }.
  14. ~ELIF[ %値 . `ViewedArrayBuffer^sl ~NEQ ε ]: ◎ Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:

    1. %~buffer ~LET %値 . `ViewedArrayBuffer^sl ◎ Let buffer be the value of value's [[ViewedArrayBuffer]] internal slot.
    2. %~buffer直列形 ~LET ? `StructuredSerializeInternal$jA( %~buffer, %蓄積用, %memory ) ◎ Let bufferSerialized be ? StructuredSerializeInternal(buffer, forStorage, memory).
    3. ~Assert: %~buffer直列形 . `Type^sl ~EQ `ArrayBuffer^l ◎ Assert: bufferSerialized.[[Type]] is "ArrayBuffer".
    4. ~IF[ %値 . `DataView^sl ~NEQ ε ] ⇒ %直列形 ~SET { `Type^sl: `ArrayBufferView^l, `Constructor^sl: `DataView^l, `ArrayBufferSerialized^sl: %~buffer直列形, `ByteLength^sl: %値 . `ByteLength^sl, `ByteOffset^sl: %値 . `ByteOffset^sl } ◎ If value has a [[DataView]] internal slot, then set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView", [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: value.[[ByteOffset]] }.
    5. ~ELSE: ◎ Otherwise:

      1. ~Assert: %値 . `TypedArrayName^sl ~NEQ ε ◎ Assert: value has a [[TypedArrayName]] internal slot.
      2. %直列形 ~SET { `Type^sl: `ArrayBufferView^l, `Constructor^sl: %値 . `TypedArrayName^sl, `ArrayBufferSerialized^sl: %~buffer直列形, `ByteLength^sl: %値 . `ByteLength^sl, `ByteOffset^sl: %値 . `ByteOffset^sl, `ArrayLength^sl: %値 . `ArrayLength^sl } ◎ Set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: value.[[TypedArrayName]], [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: value.[[ByteOffset]], [[ArrayLength]]: value.[[ArrayLength]] }.
  15. ~ELIF[ %値 . `MapData^sl ~NEQ ε ]: ◎ Otherwise, if value has [[MapData]] internal slot, then:

    1. %直列形 ~SET { `Type^sl: `Map^l, `MapData^sl: 新たな空`List$js } ◎ Set serialized to { [[Type]]: "Map", [[MapData]]: a new empty List }.
    2. %deep ~SET ~T ◎ Set deep to true.
  16. ~ELIF[ %値 . `SetData^sl ~NEQ ε ]: ◎ Otherwise, if value has [[SetData]] internal slot, then:

    1. %直列形 ~SET { `Type^sl: `Set^l, `SetData^sl: 新たな空`List$js } ◎ Set serialized to { [[Type]]: "Set", [[SetData]]: a new empty List }.
    2. %deep ~SET ~T ◎ Set deep to true.
  17. ~ELIF[ %値 は `Array^jC ~exotic~objである ]: ◎ Otherwise, if value is an Array exotic object, then:

    1. %値~長さ記述子 ~LET ? `OrdinaryGetOwnProperty$jA( %値, `length^l ) ◎ Let valueLenDescriptor be ? OrdinaryGetOwnProperty(value, "length").
    2. %値~長さ ~LET %値~長さ記述子 . `Value^sl ◎ Let valueLen be valueLenDescriptor.[[Value]].
    3. %直列形 ~SET { `Type^sl: `Array^l, `Length^sl: %値~長さ, `Properties^sl: 新たな空 `List$js } ◎ Set serialized to { [[Type]]: "Array", [[Length]]: valueLen, [[Properties]]: a new empty List }.
    4. %deep ~SET ~T ◎ Set deep to true.
  18. ~ELIF[ %値 は`直列化-可能$な`~platform~obj$である ]: ◎ Otherwise, if value is a platform object that is a serializable object:

    1. ~IF[ %値 . `Detached$sl ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If value has a [[Detached]] internal slot whose value is true, then throw a "DataCloneError" DOMException.
    2. %型~文字列 ~LET %値 の`首~interface$の識別子 ◎ Let typeString be the identifier of the primary interface of value.
    3. %直列形 ~SET { `Type^sl: %型~文字列 } ◎ Set serialized to { [[Type]]: typeString }.
    4. %deep ~SET ~T ◎ Set deep to true.
  19. ~ELIF[ %値 は`~platform~obj$である ] ⇒ ~THROW `DataCloneError$E ◎ Otherwise, if value is a platform object, then throw a "DataCloneError" DOMException.
  20. ~ELIF[ `IsCallable$jA( %値 ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ Otherwise, if IsCallable(value) is true, then throw a "DataCloneError" DOMException.
  21. ~ELIF[ %値 は[ `Prototype^sl, `Extensible^sl ]以外の内部~slotを持つ ] ⇒ ~THROW `DataCloneError$E ◎ Otherwise, if value has any internal slot other than [[Prototype]] or [[Extensible]], then throw a "DataCloneError" DOMException.

    具体的には、[ `PromiseState^sl / `WeakMapData^sl ]内部~slot。 ◎ For instance, a [[PromiseState]] or [[WeakMapData]] internal slot.

  22. ~ELIF[ %値 は~exotic~objである ] ⇒ ~THROW `DataCloneError$E ◎ Otherwise, if value is an exotic object, then throw a "DataCloneError" DOMException.

    具体的には、 proxy ~obj。 【~JS の Proxy ~obj?】 ◎ For instance, a proxy object.

  23. ~ELSE: ◎ Otherwise:

    1. %直列形 ~SET { `Type^sl: `Object^l, `Properties^sl: 新たな空`List$js } ◎ Set serialized to { [[Type]]: "Object", [[Properties]]: a new empty List }.
    2. %deep ~SET ~T ◎ Set deep to true.
  24. %memory[ %値 ] `~SET$ %直列形 ◎ Set memory[value] to serialized.
  25. ~IF[ %deep ~EQ ~T ]: ◎ If deep is true, then:

    1. ~IF[ %値 . `MapData^sl ~NEQ ε ]: ◎ If value has a [[MapData]] internal slot, then:

      1. %複製した~list ~LET 新たな空`List$js ◎ Let copiedList be a new empty List.
      2. %値 . `MapData^sl 内の`~EACH$( `Record$js %~entry ) に対し: ◎ For each Record { [[Key]], [[Value]] } entry of value.[[MapData]]:

        1. %複製した~entry ~LET 新たな `Record$js { `Key^sl: %~entry . `Key^sl, `Value^sl: %~entry . `Value^sl } ◎ Let copiedEntry be a new Record { [[Key]]: entry.[[Key]], [[Value]]: entry.[[Value]] }.
        2. ~IF[ %複製した~entry . `Key^sl ~NEQ 特殊~値 `empty^i ] ⇒ %複製した~list に %複製した~entry を`付加する$ ◎ If copiedEntry.[[Key]] is not the special value empty, append copiedEntry to copiedList.
      3. %複製した~list 内の`~EACH$( `Record$js %~entry ) に対し: ◎ For each Record { [[Key]], [[Value]] } entry of copiedList:

        1. %直列形の~key ~LET ? `StructuredSerializeInternal$jA( %~entry . `Key^sl, %蓄積用, %memory ) ◎ Let serializedKey be ? StructuredSerializeInternal(entry.[[Key]], forStorage, memory).
        2. %直列形の値 ~LET ? `StructuredSerializeInternal$jA( %~entry . `Value^sl, %蓄積用, %memory ) ◎ Let serializedValue be ? StructuredSerializeInternal(entry.[[Value]], forStorage, memory).
        3. %直列形 . `MapData^sl に { `Key^sl: %直列形の~key, `Value^sl: %直列形の値 } を`付加する$ ◎ Append { [[Key]]: serializedKey, [[Value]]: serializedValue } to serialized.[[MapData]].
    2. ~ELIF[ %値 . `SetData^sl ~NEQ ε ]: ◎ Otherwise, if value has a [[SetData]] internal slot, then:

      1. %複製した~list ~LET 新たな空`List$js ◎ Let copiedList be a new empty List.
      2. %値 . `SetData^sl 内の`~EACH$( %~entry ) に対し: ◎ For each entry of value.[[SetData]]:

        1. ~IF[ %~entry ~NEQ 特殊~値 `empty^i ] ⇒ %複製した~list に %~entry を`付加する$ ◎ If entry is not the special value empty, append entry to copiedList.
      3. %複製した~list 内の`~EACH$( %~entry ) に対し: ◎ For each entry of copiedList:

        1. %直列形の~entry ~LET ? `StructuredSerializeInternal$jA( %~entry, %蓄積用, %memory ) ◎ Let serializedEntry be ? StructuredSerializeInternal(entry, forStorage, memory).
        2. %直列形 . `SetData^sl に %直列形の~entry を`付加する$ ◎ Append serializedEntry to serialized.[[SetData]].
    3. ~ELIF[ %値 は`直列化-可能$な`~platform~obj$である ] ⇒ 適切な`直列化~手続き$( %値, %直列形, %蓄積用 ) を遂行する ◎ Otherwise, if value is a platform object that is a serializable object, then perform the appropriate serialization steps given value, serialized, and forStorage.

      `直列化~手続き$は `下位直列化@ を遂行することも必要になり得る。 これは、値 %下位~値 を入力にとり, `StructuredSerializeInternal$jA( %下位~値, %蓄積用, %memory ) を返す演算である。 (言い換えれば、`下位直列化$は,この呼出の中に整合するよう特化された `StructuredSerializeInternal$jA である。) ◎ The serialization steps may need to perform a sub-serialization. This is an operation which takes as input a value subValue, and returns StructuredSerializeInternal(subValue, forStorage, memory). (In other words, a sub-serialization is a specialization of StructuredSerializeInternal to be consistent within this invocation.)

    4. ~ELSE: ◎ Otherwise:

      1. %列挙-可能~key~list ~LET 新たな空`List$js ◎ Let enumerableKeys be a new empty List.
      2. ! %値 . `OwnPropertyKeys^sl() 内の~EACH( %~key ) に対し: ◎ For each key in ! value.[[OwnPropertyKeys]]():

        1. ~IF[ `Type$jA( %~key ) ~EQ `String^jC ]: ◎ If Type(key) is String, then:

          1. %値~記述子 ~LET ! %値 . `GetOwnProperty^sl( %~key ) ◎ Let valueDesc be ! value.[[GetOwnProperty]](key).
          2. ~IF[ %値~記述子 . `Enumerable^sl ~EQ ~T ] ⇒ %列挙-可能~key~list に %~key を`付加する$ ◎ If valueDesc.[[Enumerable]] is true, then append key to enumerableKeys.
      3. %列挙-可能~key~list 内の~EACH( %~key ) に対し: ◎ For each key in enumerableKeys:

        1. ~IF[ ! `HasOwnProperty$jA( %値, %~key ) ~EQ ~T ]: ◎ If ! HasOwnProperty(value, key) is true, then:

          1. %入力~値 ~LET ? %値 . `Get^sl( %~key, %値 ) ◎ Let inputValue be ? value.[[Get]](key, value).
          2. %出力~値 ~LET ? `StructuredSerializeInternal$jA( %入力~値, %蓄積用, %memory ) ◎ Let outputValue be ? StructuredSerializeInternal(inputValue, forStorage, memory).
          3. %直列形 . `Properties^sl に { `Key^sl: %~key, `Value^sl: %出力~値 } を`付加する$ ◎ Append { [[Key]]: key, [[Value]]: outputValue } to serialized.[[Properties]].

      注記: 上で遂行される~key収集は,~JS仕様の `EnumerableOwnProperties$jA 演算によく似ているが、その演算のように~keyたちを未指定の方式で並替えることなく, `OwnPropertyKeys^sl 内部~methodが供する決定的順序を利用する。 `JAVASCRIPT$r ◎ 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. [JAVASCRIPT]

  26. ~RET %直列形 ◎ Return serialized.

`StructuredSerializeInternal$jA から生産される `Record$js は、参照を循環させるような,他の~recordへの “~pointer” を包含し得ることに要注意。 例えば、次の~JS~objを `StructuredSerializeInternal$jA に渡したとするとき: ◎ It's important to realize that the Records produced by StructuredSerializeInternal might contain "pointers" to other records that create circular references. For example, when we pass the following JavaScript object into StructuredSerializeInternal:

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

次の結果が生産される: ◎ it produces the following result:

{
  `Type^sl: `Object^l,
  `Properties^sl: «
    {
      `Key^sl: `myself^l,
      `Value^sl: `<この構造~全体を指す~pointer>^i
    }
  »
}

2.7.4. `StructuredSerialize^jA ( %値 )

  1. ~RET ? `StructuredSerializeInternal$jA( %値, ~F ) ◎ Return ? StructuredSerializeInternal(value, false).

2.7.5. `StructuredSerializeForStorage^jA ( %値 )

  1. ~RET ? `StructuredSerializeInternal$jA( %値, ~T ) ◎ Return ? StructuredSerializeInternal(value, true).

2.7.6. `StructuredDeserialize^jA ( %直列形, %宛先~Realm [ , %memory ] )

`StructuredDeserialize$jA 抽象演算は、以前に[ `StructuredSerialize$jA / `StructuredSerializeForStorage$jA ]が生産した `Record$js %直列形 を入力にとり,[ %宛先~Realm に属する新たな~JS値 ]に逆直列化する: ◎ The StructuredDeserialize abstract operation takes as input a Record serialized, which was previously produced by StructuredSerialize or StructuredSerializeForStorage, and deserializes it into a new JavaScript value, created in targetRealm.

この処理-は、例外を投出し得る — 例えば,新たな~obj用に~memoryを割当てようと試行したとき(とりわけ, `ArrayBuffer^jC ~obj)。 ◎ This process can throw an exception, for example when trying to allocate memory for the new objects (especially ArrayBuffer objects).

  1. ~IF[ %memory は給されてない ] ⇒ %memory ~LET 空`~map$ ◎ If memory was not supplied, let memory be an empty map.

    注記: %memory ~mapの目的は、~objが重ねて逆直列化されるのを避けることにある。 これには、循環参照を保全して,~graphにおける~objの重複を識別することが必要になる。 ◎ 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.

  2. ~IF[ %memory[ %直列形 ] ~NEQ ε ] ⇒ ~RET %memory[ %直列形 ] ◎ If memory[serialized] exists, then return memory[serialized].
  3. %deep ~LET ~F ◎ Let deep be false.
  4. %値 ~LET ε ◎ Let value be an uninitialized value.
  5. %直列形 . `Type^sl に応じて: ◎ ↓

    1. `primitive^l ⇒ %値 ~SET %直列形 . `Value^sl ◎ If serialized.[[Type]] is "primitive", then set value to serialized.[[Value]].
    2. `Boolean^l ⇒ %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `Boolean^jC ~obj ⇒ . `BooleanData^sl ~SET %直列形 . `BooleanData^sl ◎ Otherwise, if serialized.[[Type]] is "Boolean", then set value to a new Boolean object in targetRealm whose [[BooleanData]] internal slot value is serialized.[[BooleanData]].
    3. `Number^l ⇒ %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `Number^jC ~obj ⇒ . `NumberData^sl ~SET %直列形 . `NumberData^sl ◎ Otherwise, if serialized.[[Type]] is "Number", then set value to a new Number object in targetRealm whose [[NumberData]] internal slot value is serialized.[[NumberData]].
    4. `BigInt^l `JSBIGINT$r ⇒ %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `BigInt^jC ~obj ⇒ . `BigIntData^sl ~SET %直列形 . `BigIntData^sl ◎ Otherwise, if serialized.[[Type]] is "BigInt", then set value to a new BigInt object in targetRealm whose [[BigIntData]] internal slot value is serialized.[[BigIntData]]. [JSBIGINT]
    5. `String^l ⇒ %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `String^jC ~obj ⇒ . `StringData^sl ~SET %直列形 . `StringData^sl ◎ Otherwise, if serialized.[[Type]] is "String", then set value to a new String object in targetRealm whose [[StringData]] internal slot value is serialized.[[StringData]].
    6. `Date^l ⇒ %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `Date^jC ~obj ⇒ . `DateValue^sl ~SET %直列形 . `DateValue^sl ◎ Otherwise, if serialized.[[Type]] is "Date", then set value to a new Date object in targetRealm whose [[DateValue]] internal slot value is serialized.[[DateValue]].
    7. `RegExp^l ⇒ %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `RegExp^jC ~obj ⇒# . `RegExpMatcher^sl ~SET %直列形 . `RegExpMatcher^sl, . `OriginalSource^sl ~SET %直列形 . `OriginalSource^sl, . `OriginalFlags^sl ~SET %直列形 . `OriginalFlags^sl ◎ 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]].
    8. `SharedArrayBuffer^l: ◎ Otherwise, if serialized.[[Type]] is "SharedArrayBuffer", then:

      1. ~IF[ %宛先~Realm に対応する`~agent-cluster$ ~NEQ %直列形 . `AgentCluster^l ] ⇒ ~THROW `DataCloneError$E ◎ If targetRealm's corresponding agent cluster is not serialized.[[AgentCluster]], then then throw a "DataCloneError" DOMException.
      2. %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `SharedArrayBuffer^jC ~obj ⇒# . `ArrayBufferData^sl ~SET %直列形 . `ArrayBufferData^sl, . `ArrayBufferByteLength^sl ~SET %直列形 . `ArrayBufferByteLength^sl ◎ Otherwise, set value to a new SharedArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]] and whose [[ArrayBufferByteLength]] internal slot value is serialized.[[ArrayBufferByteLength]].
    9. `ArrayBuffer^l: ◎ Otherwise, if serialized.[[Type]] is "ArrayBuffer", then\

      1. %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `ArrayBuffer^jC ~obj ⇒# . `ArrayBufferData^sl ~SET %直列形 . `ArrayBufferData^sl, . `ArrayBufferByteLength^sl ~SET %直列形 . `ArrayBufferByteLength^sl ◎ 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]].

        ここで例外が投出されたときは、~catchして ⇒ ~THROW `DataCloneError$E ◎ If this throws an exception, catch it, and then throw a "DataCloneError" DOMException.

      注記: この段にて例外が投出されるのは、 `ArrayBuffer^jC ~objを作成するに十分な~memoryが可用でない場合である。 ◎ This step might throw an exception if there is not enough memory available to create such an ArrayBuffer object.

    10. `ArrayBufferView^l: ◎ Otherwise, if serialized.[[Type]] is "ArrayBufferView", then:

      1. %逆直列形の~ArrayBuffer ~LET ? `StructuredDeserialize$jA( %直列形 . `ArrayBufferSerialized^sl, %宛先~Realm, %memory ) ◎ Let deserializedArrayBuffer be ? StructuredDeserialize(serialized.[[ArrayBufferSerialized]], targetRealm, memory).
      2. ~IF[ %直列形 . `Constructor^sl ~EQ `DataView^l ] ⇒ %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `DataView^jC ~obj ⇒# . `ViewedArrayBuffer^sl ~SET %逆直列形の~ArrayBuffer, . `ByteLength^sl ~SET %直列形 . `ByteLength^sl, . `ByteOffset^sl ~SET %直列形 . `ByteOffset^sl ◎ If serialized.[[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]].
      3. ~ELSE ⇒ %値 ~SET [ %直列形 . `Constructor^sl が与える構築子を利用し, 次のようにされた, %宛先~Realm 内の新たな有型~配列~obj ] ⇒# . `ViewedArrayBuffer^sl ~SET %逆直列形の~ArrayBuffer, . `TypedArrayName^sl ~SET %input . `Constructor^sl, . `ByteLength^sl ~SET %直列形 . `ByteLength^sl, . `ByteOffset^sl ~SET %直列形 . `ByteOffset^sl, . `ArrayLength^sl ~SET %直列形 . `ArrayLength^sl ◎ Otherwise, set value to a new typed array object in targetRealm, using the constructor given by serialized.[[Constructor]], whose [[ViewedArrayBuffer]] internal slot value is deserializedArrayBuffer, whose [[TypedArrayName]] internal slot value is serialized.[[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]].
    11. `Map^l: ◎ Otherwise, if serialized.[[Type]] is "Map", then:

      1. %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `Map^jC ~obj ⇒ . `MapData^sl ~SET 新たな空`List$js ◎ Set value to a new Map object in targetRealm whose [[MapData]] internal slot value is a new empty List.
      2. %deep ~SET ~T ◎ Set deep to true.
    12. `Set^l: ◎ Otherwise, if serialized.[[Type]] is "Set", then:

      1. %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `Set^jC ~obj ⇒ . `SetData^sl ~SET 新たな空`List$js ◎ Set value to a new Set object in targetRealm whose [[SetData]] internal slot value is a new empty List.
      2. %deep ~SET ~T ◎ Set deep to true.
    13. `Array^l: ◎ Otherwise, if serialized.[[Type]] is "Array", then:

      1. %出力~prototype ~LET %宛先~Realm 内の `ArrayPrototype$jI 内在的~obj ◎ Let outputProto be the %ArrayPrototype% intrinsic object in targetRealm.
      2. %値 ~SET ! `ArrayCreate$jA( %直列形 . `Length^sl, %出力~prototype ) ◎ Set value to ! ArrayCreate(serialized.[[Length]], outputProto).
      3. %deep ~SET ~T ◎ Set deep to true.
    14. `Object^l: ◎ Otherwise, if serialized.[[Type]] is "Object", then:

      1. %値 ~SET %宛先~Realm 内の新たな `Object^jC ◎ Set value to a new Object in targetRealm.
      2. %deep ~SET ~T ◎ Set deep to true.
    15. その他: ◎ Otherwise:

      1. %~interface名 ~LET %直列形 . `Type^sl ◎ Let interfaceName be serialized.[[Type]].
      2. ~IF[ %~interface名 により識別される~interfaceは %宛先~Realm 内に公開されていない ] ⇒ ~THROW `DataCloneError$E ◎ If the interface identified by interfaceName is not exposed in targetRealm, then throw a "DataCloneError" DOMException.
      3. %値 ~SET %宛先~Realm 内に作成される, %~interface名 により識別される~interfaceの新たな~instance ◎ Set value to a new instance of the interface identified by interfaceName, created in targetRealm.
      4. %deep ~SET ~T ◎ Set deep to true.
  6. %memory[ %直列形 ] `~SET$ %値 ◎ Set memory[serialized] to value.
  7. ~IF[ %deep ~EQ ~F ] ⇒ ~RET %値 ◎ ↓
  8. %直列形 . `Type^sl に応じて: ◎ If deep is true, then:

    1. `Map^l: ◎ If serialized.[[Type]] is "Map", then:

      1. %直列形 . `MapData^sl 内の`~EACH$( `Record$js %~entry ) に対し: ◎ For each Record { [[Key]], [[Value]] } entry of serialized.[[MapData]]:

        1. %逆直列形の~key ~LET ? `StructuredDeserialize$jA( %~entry . `Key^sl, %宛先~Realm, %memory ) ◎ Let deserializedKey be ? StructuredDeserialize(entry.[[Key]], targetRealm, memory).
        2. %逆直列形の値 ~LET ? `StructuredDeserialize$jA( %~entry . `Value^sl, %宛先~Realm, %memory ) ◎ Let deserializedValue be ? StructuredDeserialize(entry.[[Value]], targetRealm, memory).
        3. %値 . `MapData^sl に { `Key^sl: %逆直列形の~key, `Value^sl: %逆直列形の値 } を`付加する$ ◎ Append { [[Key]]: deserializedKey, [[Value]]: deserializedValue } to value.[[MapData]].
    2. `Set^l: ◎ Otherwise, if serialized.[[Type]] is "Set", then:

      1. %直列形 . `SetData^sl 内の`~EACH$( %~entry ) に対し: ◎ For each entry of serialized.[[SetData]]:

        1. %逆直列形の~entry ~LET ? `StructuredDeserialize$jA( %~entry, %宛先~Realm, %memory ) ◎ Let deserializedEntry be ? StructuredDeserialize(entry, targetRealm, memory).
        2. %値 . `SetData^sl に %逆直列形の~entry を`付加する$ ◎ Append deserializedEntry to value.[[SetData]].
    3. `Array^l / `Object^l: ◎ Otherwise, if serialized.[[Type]] is "Array" or "Object", then:

      1. %直列形 . `Properties^sl 内の`~EACH$( `Record$js %~entry ) に対し: ◎ For each Record { [[Key]], [[Value]] } entry of serialized.[[Properties]]:

        1. %逆直列形の値 ~LET ? `StructuredDeserialize$jA( %~entry . `Value^sl, %宛先~Realm, %memory ) ◎ Let deserializedValue be ? StructuredDeserialize(entry.[[Value]], targetRealm, memory).
        2. %結果 ~LET ! `CreateDataProperty$jA( %値, %~entry . `Key^sl, %逆直列形の値 ) ◎ Let result be ! CreateDataProperty(value, entry.[[Key]], deserializedValue).
        3. ~Assert: %結果 ~EQ ~T ◎ Assert: result is true.
    4. その他: ◎ Otherwise:

      1. %直列形 . `Type^sl により識別される~interface用に適切な`逆直列化~手続き$( %直列形, %値 ) を遂行する ◎ Perform the appropriate deserialization steps for the interface identified by serialized.[[Type]], given serialized and value.

        `逆直列化~手続き$は、 `下位逆直列化@ を遂行することも必要になり得る。 これは、以前に直列化された `Record$js %下位直列形 を入力にとり, `StructuredDeserialize$jA( %下位直列形, %宛先~Realm, %memory ) を返す演算である(言い換えれば、`下位逆直列化$は,この呼出の中で整合するよう特化された `StructuredDeserialize$jA である。) ◎ 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.)

  9. ~RET %値 ◎ Return value.

2.7.7. `StructuredSerializeWithTransfer^jA ( %値, %転送-~list )

  1. %memory ~LET 空`~map$ ◎ Let memory be an empty map.

    注記: `StructuredSerializeInternal$jA による通常の用法に加えて,この~algoにおける %memory は、[ `StructuredSerializeInternal$jA が %転送-~list 内の~itemを無視して,代わりに自前の取扱いを行えるようにする ]ことを確保するためにも利用される。 ◎ In addition to how it is used normally by StructuredSerializeInternal, in this algorithm memory is also used to ensure that StructuredSerializeInternal ignores items in transferList, and let us do our own handling instead.

  2. %転送-~list 内の`~EACH$( %転送対象 ) に対し: ◎ For each transferable of transferList:

    1. ~IF[ %転送対象 . `ArrayBufferData^sl ~EQ ε ]~AND[ %転送対象 . `Detached$sl ~EQ ε ] ⇒ ~THROW `DataCloneError$E ◎ If transferable has neither an [[ArrayBufferData]] internal slot nor a [[Detached]] internal slot, then throw a "DataCloneError" DOMException.
    2. ~IF[ %転送対象 . `ArrayBufferData^sl ~NEQ ε ]~AND[ ! `IsSharedArrayBuffer$jA( %転送対象 ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If transferable has an [[ArrayBufferData]] internal slot and ! IsSharedArrayBuffer(transferable) is true, then throw a "DataCloneError" DOMException.
    3. ~IF[ %memory[ %転送対象 ] ~NEQ ε ] ⇒ ~THROW `DataCloneError$E ◎ If memory[transferable] exists, then throw a "DataCloneError" DOMException.
    4. %memory[ %転送対象 ] `~SET$ { `Type^sl: 初期化されていない値 } 【実質的には,空の~record】 ◎ Set memory[transferable] to { [[Type]]: an uninitialized value }.

      注記: %転送対象 はまだ転送されない — 転送には副作用があり, `StructuredSerializeInternal$jA は最初に投出-可能になる必要があるので。 ◎ transferable is not transferred yet as transferring has side effects and StructuredSerializeInternal needs to be able to throw first.

  3. %直列形 ~LET ? `StructuredSerializeInternal$jA( %値, ~F, %memory ) ◎ Let serialized be ? StructuredSerializeInternal(value, false, memory).
  4. %転送-~data保持体~list ~LET 新たな空`List$js ◎ Let transferDataHolders be a new empty List.
  5. %転送-~list 内の`~EACH$( %転送対象 ) に対し: ◎ For each transferable of transferList:

    1. ~IF[ %転送対象 . `ArrayBufferData^sl ~NEQ ε ]~AND[ ! `IsDetachedBuffer$jA( %転送対象 ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If transferable has an [[ArrayBufferData]] internal slot and ! IsDetachedBuffer(transferable) is true, then throw a "DataCloneError" DOMException.
    2. ~IF[ %転送対象 . `Detached$sl ~NEQ ε ]~AND[ %転送対象 . `Detached$sl ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If transferable has a [[Detached]] internal slot and transferable.[[Detached]] is true, then throw a "DataCloneError" DOMException.
    3. %~data保持体 ~LET %memory[ %転送対象 ] ◎ Let dataHolder be memory[transferable].
    4. ~IF[ %転送対象 . `ArrayBufferData^sl ~NEQ ε ]: ◎ If transferable has an [[ArrayBufferData]] internal slot, then:

      1. %~data保持体 の ⇒# . `Type^sl ~SET `ArrayBuffer^l, . `ArrayBufferData^sl ~SET %転送対象 . `ArrayBufferData^sl, . `ArrayBufferByteLength^sl ~SET %転送対象 . `ArrayBufferByteLength^sl ◎ Set dataHolder.[[Type]] to "ArrayBuffer". ◎ Set dataHolder.[[ArrayBufferData]] to transferable.[[ArrayBufferData]]. ◎ Set dataHolder.[[ArrayBufferByteLength]] to transferable.[[ArrayBufferByteLength]].
      2. ! `DetachArrayBuffer$jA( %転送対象 ) を遂行する ◎ Perform ! DetachArrayBuffer(transferable).
    5. ~ELSE: ◎ Otherwise:

      1. ~Assert: %転送対象 は`転送-可能$な`~platform~obj$である ◎ Assert: transferable is a platform object that is a transferable object.
      2. %~interface名 ~LET %転送対象 の`首~interface$の識別子 ◎ Let interfaceName be the identifier of the primary interface of transferable.
      3. %~data保持体 . `Type^sl ~SET %~interface名 ◎ Set dataHolder.[[Type]] to interfaceName.
      4. %~interface名 により識別される~interfaceに適切な`転送-手続き$( %転送対象, %~data保持体 ) を遂行する ◎ Perform the appropriate transfer steps for the interface identified by interfaceName, given transferable and dataHolder.
      5. %転送対象 . `Detached$sl ~SET ~T ◎ Set transferable.[[Detached]] to true.
    6. %転送-~data保持体~list に %~data保持体 を`付加する$ ◎ Append dataHolder to transferDataHolders.
  6. ~RET { `Serialized^sl: %直列形, `TransferDataHolders^sl: %転送-~data保持体~list } ◎ Return { [[Serialized]]: serialized, [[TransferDataHolders]]: transferDataHolders }.

2.7.8. `StructuredDeserializeWithTransfer^jA ( %転送-を伴う直列化-結果, %宛先~Realm )

  1. %memory ~LET 空`~map$ ◎ Let memory be an empty map.

    注記: `StructuredSerializeWithTransfer$jA と相似的に、 `StructuredDeserialize$jA による通常の用法に加えて,この~algoにおける %memory は、[ `StructuredSerializeInternal$jA が[ %転送-を伴う直列化-結果 . [[TransferDataHolders]] 内の~item ]を無視して,代わりに自前の取扱いを行えるようにする。 ◎ Analogous to StructuredSerializeWithTransfer, in addition to how it is used normally by StructuredDeserialize, in this algorithm memory is also used to ensure that StructuredDeserialize ignores items in serializeWithTransferResult.[[TransferDataHolders]], and let us do our own handling instead.

  2. %転送-済み値~list ~LET 新たな空`List$js ◎ Let transferredValues be a new empty List.
  3. %転送-を伴う直列化-結果 . `TransferDataHolders^sl 内の`~EACH$( %転送-~data保持体 ) に対し: ◎ For each transferDataHolder of serializeWithTransferResult.[[TransferDataHolders]]:

    1. %値 ~LET ε ◎ Let value be an uninitialized value.
    2. ~IF[ %転送-~data保持体 . `Type^sl ~EQ `ArrayBuffer^l ] ⇒ %値 ~SET 次のようにされた, %宛先~Realm 内の新たな `ArrayBuffer^jC ~obj ⇒# . `ArrayBufferData^sl ~SET %転送-~data保持体 . `ArrayBufferData^sl, . `ArrayBufferByteLength^sl ~SET %転送-~data保持体 . `ArrayBufferByteLength^sl ◎ If transferDataHolder.[[Type]] is "ArrayBuffer", then set value to a new ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is transferDataHolder.[[ArrayBufferData]], and whose [[ArrayBufferByteLength]] internal slot value is transferDataHolder.[[ArrayBufferByteLength]].

      注記: `ArrayBufferData^sl が占めている元の~memoryが 逆直列化の間も~access可能な事例では、この段は,およそ例外を投出しないであろう — 新たな~memoryを割当てる必要はないので。 代わりに,その元の~memoryが新たな `ArrayBuffer^jC に転送されることになる。 これは、例えば,~source~Realmと宛先~Realmの両者とも同じ~process内にあるときに該当し得る ◎ 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.

    3. ~ELSE: ◎ Otherwise:

      1. %~interface名 ~LET %転送-~data保持体 . `Type^sl ◎ Let interfaceName be transferDataHolder.[[Type]].
      2. ~IF[ %~interface名 により識別される~interfaceは %宛先~Realm 内に公開されていない ] ⇒ ~THROW `DataCloneError$E ◎ If the interface identified by interfaceName is not exposed in targetRealm, then throw a "DataCloneError" DOMException.
      3. %値 ~SET %宛先~Realm 内に作成される, %~interface名 により識別される~interfaceの新たな~instance ◎ Set value to a new instance of the interface identified by interfaceName, created in targetRealm.
      4. %~interface名 により識別される~interfaceに適切な`転送-受信-時の手続き$( %転送-~data保持体, %値 ) を遂行する ◎ Perform the appropriate transfer-receiving steps for the interface identified by interfaceName given transferDataHolder and value.
    4. %memory[ %転送-~data保持体 ] ~SET %値 ◎ Set memory[transferDataHolder] to value.
    5. %転送-済み値~list に %値 を`付加する$ ◎ Append value to transferredValues.
  4. %逆直列形 ~LET ? `StructuredDeserialize$jA( %転送-を伴う直列化-結果 . `Serialized^sl, %宛先~Realm, %memory ) ◎ Let deserialized be ? StructuredDeserialize(serializeWithTransferResult.[[Serialized]], targetRealm, memory).
  5. ~RET { `Deserialized^sl: %逆直列形, `TransferredValues^sl: %転送-済み値~list } ◎ Return { [[Deserialized]]: deserialized, [[TransferredValues]]: transferredValues }.

2.7.9. 他の仕様からの直列化と転送-の遂行-法

他の仕様は、ここに定義した抽象演算を利用してよい。 以下に、各種 抽象演算が概していつ有用になるかについての手引きを,例とともに供する: ◎ Other specifications may use the abstract operations defined here. The following provides some guidance on when each abstract operation is typically useful, with examples.

`StructuredSerializeWithTransfer$jA
`StructuredDeserializeWithTransfer$jA
宛先~Realmは事前に既知でないとき, 別の`~Realm$へ,転送-~listも伴わせて値を~cloneするとき。 この事例では,直列化の段は即時に遂行できる一方で、逆直列化の段は 宛先~Realmが既知になるまで遅延される。 ◎ 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()$m は、行先~Realmは `MessagePort$I が`搬送-済み$になるまで既知でないので,この抽象演算を組みで利用する。 ◎ messagePort.postMessage() uses this pair of abstract operations, as the destination Realm is not known until the MessagePort has been shipped.
`StructuredSerialize$jA
`StructuredSerializeForStorage$jA
`StructuredDeserialize$jA
所与の値に対し,`~Realm$から独立な~snapshotを作成するとき — 不定~~期間~保存でき、後に,場合によっては複数~回にわたり~JS値に~~復元されるような。 ◎ Creating a JavaScript Realm-independent snapshot of a given value which can be saved for an indefinite amount of time, and then reified back into a JavaScript value later, possibly multiple times.
`StructuredSerializeForStorage$jA は、直列化が,~Realm間で渡されず持続的に格納されると見込まれる状況に利用できる。 `SharedArrayBuffer$I ~objを直列化しようと試みたときは、投出する — 共用~memory内に格納しても無為なので。 同様に,所与の`~platform~obj$に~custom`直列化~手続き$がある場合、[ %蓄積用 引数 ~EQ ~T ]の下では,[ 投出する / 場合によっては挙動が異なる ]こともある。 ◎ StructuredSerializeForStorage can be used for situations where the serialization is anticipated to be stored in a persistent manner, instead of passed between Realms. It throws when attempting to serialize SharedArrayBuffer objects, since storing shared memory does not make sense. Similarly, it can throw or possibly have different behavior when given a platform object with custom serialization steps when the forStorage argument is true.
`history.pushState()$m / `history.replaceState()$m は、作者から給された状態~objに `StructuredSerializeForStorage$jA を利用し,それを適切な`~session履歴~entry$内に`直列形の状態$で格納する。 `history.state$m ~propは、 `StructuredDeserialize$jA を利用して,元々給された状態~objの~cloneを返す。 ◎ history.pushState() and history.replaceState() use StructuredSerializeForStorage on author-supplied state objects, storing them as serialized state in the appropriate session history entry. Then, StructuredDeserialize is used so that the history.state property can return a clone of the originally-supplied state object.
`broadcastChannel.postMessage()$m は、その入力に対し `StructuredSerialize$jA を利用した結果に対し, `StructuredDeserialize$jA を複数~回~利用して、~broadcastされている各 行先~用に新規の~cloneを生産する。 行先が複数ある状況では、転送は~~意味を成さないことに注意。 ◎ 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.
~filesystemに~JS値を持続化させるような~APIも、その入力に `StructuredSerializeForStorage$jA を利用し,その出力に `StructuredDeserialize$jA を利用する。 ◎ Any API for persisting JavaScript values to the filesystem would also use StructuredSerializeForStorage on its input and StructuredDeserialize on its output.

一般に、~callする側は,~JS値の代わりに~WebIDL値を渡してもよい — これは、これらの~algoを呼出す前に,暗黙的な`~JS値への変換$を遂行するものと解される。 ◎ 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.

注記: この仕様は, “有構造~clone” ~algo, および より近過去には `StructuredClone^jA 抽象演算も定義していたが、それらは除去された — 既知の[ 実施におけるそれらの利用 ]すべては、直列化と逆直列化の手続きに分離することで,より上手く~~働くようになるので。 ◎ 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する側が[ 作者~codeが~UA~methodの中へ~callした結果として同期的に呼出されてはいない ]場合、それが任意の~obj上で遂行されている場合には,抽象演算[ `StructuredSerialize$jA / `StructuredSerializeForStorage$jA / `StructuredSerializeWithTransfer$jA ]を呼出す前に,適正に[ `~scriptを走らすために準備する$ / `~callbackを走らすために準備する$ ]よう注意し~MUST。 このことは、必要とされる — 直列化~処理-は、その~~最終的な深い直列化~手続きの一部として,作者により定義される~accessorを呼出すこともあり、その~accessorは[[ `入口~某$/`現任の某$ の概念が 適正に設定してある ]ことに依拠するような演算 ]の中へ~callすることもあるので。 ◎ 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 StructuredSerialize, StructuredSerializeForStorage, 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()$m は、その引数に対し `StructuredSerializeWithTransfer$jA を遂行するが、注意深く,自身の~algoの同期的~部位の内側で即時に行うので、[ `~scriptを走らすために準備する$ / `~callbackを走らすために準備する$ ]必要なく,この~algoを利用できる。 ◎ window.postMessage() performs StructuredSerializeWithTransfer on its arguments, but is careful to do so immediately, inside the synchronous portion of its algorithm. Thus it is able to use the algorithms without needing to prepare to run script and prepare to run a callback.

対照的に、 `StructuredSerialize$jA を利用して,[ 作者から給された何らかの~objを,`~event-loop$上の`~task$から 直に毎回~直列化する ]ような ~APIがあるとするなら、前もって適切な準備が遂行されることを確保する必要がある。 現時点では、そのような~APIは~platform上にないことが知られている — 通例的には,作者~codeに同期して,事前に直列化を遂行しておく方が単純になる。 ◎ 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 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.