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

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

【この訳に固有の表記規約】

上述に加えて、この訳では,次のような略記法を導入する:

  • “%O . `~Foo^sl” のような表記は、[ ~JS~obj / ~JS`~Record$js ] %O 上の 名前 `~Foo^l の[[ 内部~slot または 内部~method ]/ ~field ]を表すとする。 %O が明らかな所では、単に “ . `~Foo^sl” のようにも記される。
  • 代入の右辺や比較式に現れる “%O . `~Foo^sl” のような表記は、 ~Foo[ 内部~slot / ~field ]の値を表す。 同様に, “%O . `~Foo^sl(…)” は、 ~Foo 内部~methodを~callした結果の値を表す。
  • “%O . `~Foo^sl ~NEQ ε” という表記は、 %O には,名前 `~Foo^l の[ 内部~slot/内部~method/~field ]が在ることを意味する。 “%O . `~Foo^sl ~EQ ε” はその否定(無いこと)を意味する。

また,~JS~Realmは一律に`~Realm$と略記する。 その他、この訳の,~algoや定義の記述に利用されている各種記号( ~LET, ε, ~IF, ~THROW, 等々)の意味や定義の詳細は、~SYMBOL_DEF_REFを~~参照されたし。

2.8.1. 直列化-可能な~obj

`直列化-可能$な~objは、所与の`~Realm$が何であれ,それに独立な仕方で直列化され, 後に逆直列化されることを~supportする 【逆直列化( deserialize ) — 字義通り,直列化された結果から元に復元すること】 。 これにより、それを~diskに格納して後に復旧したり,`~agent$, あるいは`~agent~cluster$の境界まで越えて~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 agent and even agent cluster boundaries.

~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$は、その`首~interface$に `Serializable@xA ~IDL`拡張属性$が付与されているならば、`直列化-可能$である。 そのような~interfaceは、次の~algoも定義しなければナラナイ(括弧内は入力): ◎ Platform objects can be serializable objects if their primary interface is decorated with the [Serializable] IDL extended attribute. Such interfaces must also define the following algorithms:

`直列化~手続き@( `~platform~obj$ %値, `~Record$js %直列形, ~boolean %~storage用 ) ◎ serialization steps, taking a platform object value, a Record serialized, and a boolean forStorage
%値 内の~dataを %直列形 の各~fieldの中に直列化するための手続き。 %直列形 の中に直列化される結果の~dataは、どの`~Realm$からも独立でなければナラナイ。 ◎ 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に関連な場合を除き, %~storage用 引数は省略するベキである。 ◎ 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 拡張属性は ⇒# 引数をとってはナラナイ。 ~interface以外に現れてはナラナイ。 ~interfaceに現れるのは一度限りでなければナラナイ。 ◎ The [Serializable] extended attribute must take no arguments, and must only appear on an interface. It must not appear more than once on an interface.

所与の`~platform~obj$に対し,その[ 直列化/逆直列化 ]処理nにおいて考慮されるのは、~objの`首~interface$に限られる。 したがって,~interfaceが継承が孕むように定義されている場合、継承~連鎖を成す各 `Serializable$xA 注釈-付き~interfaceは、自立的な[ `直列化~手続き$, `逆直列化~手続き$ ]を — 継承した~interfaceから来ている重要な~dataがあれば それも織り込むように — 定義する必要がある。 ◎ For a given platform object, only the object's primary interface is considered during the (de)serialization process. Thus, if inheritance is involved in defining the interface, each [Serializable]-annotated interface in the inheritance chain needs to define standalone serialization steps and deserialization steps, including taking into account any important data that might come from inherited interfaces.

ある~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^sl ~SET %値 の `~BestFriend^i 値の`下位-直列化$ ◎ Let serializedBestFriend be the sub-serialization of value's associated best friend value. ◎ Set serialized.[[BestFriend]] to serializedBestFriend.
`逆直列化~手続き$ ◎ deserialization steps
  1. %値 の `~name^i 値 ~SET %直列形 . `Name^sl ◎ Set value's associated name value to serialized.[[Name]].
  2. %値 の `~BestFriend^i ~SET %直列形 . `BestFriend^sl の`下位-逆直列化$ ◎ Let deserializedBestFriend be the sub-deserialization of serialized.[[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$から別の~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.8.2. 転送-可能な~obj

`転送-可能$な~objは、`~agent$間をまたぐ転送ngを~supportする。 ~obj %O の転送ngは、実質的に, %O と同じ下層の~dataを参照するような~objを作成し直す一方で,転送-側から %O を切離すことである。 これは、高価な資源の所有権を転送するときに,有用になる。 ~objには`転送-可能$でないものもあり、`転送-可能$なものでも そのすべての側面が転送-時に保全されるとは限らない。 ◎ Transferable objects support being transferred across agents. 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.

注記: 転送ngは、不可逆であり,冪等でない演算である。 ~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$は、その`首~interface$に `Transferable@xA ~IDL`拡張属性$が付与されているならば、`転送-可能$である。 そのような~interfaceは,次の~algoも定義しなければナラナイ(括弧内は入力): ◎ Platform objects can be transferable objects if their primary interface is 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$からも独立でなければナラナイ。 ◎ 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 拡張属性は ⇒# 引数をとってはナラナイ。 ~interface以外に現れてはナラナイ。 ~interfaceに現れるのは一度限りでなければナラナイ。 ◎ The [Transferable] extended attribute must take no arguments, and must only appear on an interface. It must not appear more than once on an interface.

所与の`~platform~obj$に対し,その転送ng処理nにおいて考慮されるのは、~objの`首~interface$に限られる。 したがって,~interfaceが継承が孕むように定義されている場合、継承~連鎖を成す各 `Transferable$xA 注釈-付き~interfaceは、自立的な[ `転送-手続き$, `転送-受信-時の手続き$ ]を — 継承した~interfaceから来ている重要な~dataがあれば それも織り込むように — 定義する必要がある。 ◎ For a given platform object, only the object's primary interface is considered during the transferring process. Thus, if inheritance is involved in defining the interface, each [Transferable]-annotated interface in the inheritance chain needs to define standalone transfer steps and transfer-receiving steps, including taking into account any important data that might come from inherited interfaces.

`~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.8.3. `StructuredSerializeInternal^jA ( %値, %~storage用 [ , %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: %値 } ◎ If Type(value) is Undefined, Null, Boolean, Number, BigInt, or String, then return { [[Type]]: "primitive", [[Value]]: value }.
  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 } ◎ Otherwise, if value has a [[BigIntData]] internal slot, then set serialized to { [[Type]]: "BigInt", [[BigIntData]]: value.[[BigIntData]] }.
  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[ ~NOABRUPT `IsSharedArrayBuffer$jA( %値 ) ~EQ ~T ]: ◎ If ! IsSharedArrayBuffer(value) is true, then:

      1. %~agent~cluster ~LET `~surrounding~agent$の`~agent~cluster$ ◎ Let agentCluster be the surrounding agent's agent cluster.
      2. ~IF[ %~agent~cluster の`非同一-生成元~隔離-済み$ ~EQ ~F ] ⇒ ~THROW `DataCloneError$E ◎ If agentCluster's cross-origin isolated is false, then throw a "DataCloneError" DOMException.

        注記: この検査は、直列化するときに限り必要になる(逆直列化するときは必要ない) — `非同一-生成元~隔離-済み$は時間とともに変化することはなく, `SharedArrayBuffer$I は`~agent~cluster$から離れ得ないので。 ◎ This check is only needed when serializing (and not when deserializing) as cross-origin isolated cannot change over time and a SharedArrayBuffer cannot leave an agent cluster.

      3. ~IF[ %~storage用 ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If forStorage is true, then throw a "DataCloneError" DOMException.
      4. %直列形 ~SET { `Type^sl: `SharedArrayBuffer^l, `ArrayBufferData^sl: %値 . `ArrayBufferData^sl, `ArrayBufferByteLength^sl: %~size, `AgentCluster^sl: %~agent~cluster } ◎ Set serialized to { [[Type]]: "SharedArrayBuffer", [[ArrayBufferData]]: value.[[ArrayBufferData]], [[ArrayBufferByteLength]]: size, [[AgentCluster]]: agentCluster }.
    3. ~ELSE: ◎ Otherwise:

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

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

      3. ~NOABRUPT `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 ~ABRUPT `StructuredSerializeInternal$jA( %~buffer, %~storage用, %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[ %値 . `ErrorData^sl ~NEQ ε ]~AND[ %値 は`~platform~obj$でない ]: ◎ Otherwise, if value has an [[ErrorData]] internal slot and value is not a platform object, then:

    1. %名前 ~LET ~ABRUPT `Get$jA( %値, `name^l ) ◎ Let name be ? Get(value, "name").
    2. ~IF[ %名前 ~NIN { `Error^l, `EvalError^l, `RangeError^l, `ReferenceError^l, `SyntaxError^l, `TypeError^l, `URIError^l } ] ⇒ %名前 ~SET `Error^l ◎ If name is not one of "Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", or "URIError", then set name to "Error".
    3. %値~message記述子 ~LET ~ABRUPT %値 . `GetOwnProperty^sl( `message^l ) ◎ Let valueMessageDesc be ? value.[[GetOwnProperty]]("message").
    4. %~message ~LET `IsDataDescriptor$jA( %値~message記述子 ) に応じて ⇒# ~F ならば `undefined^jv / ~ELSE_ ~ABRUPT `ToString$jA( %値~message記述子 . `Value^sl ) ◎ Let message be undefined if IsDataDescriptor(valueMessageDesc) is false, and ? ToString(valueMessageDesc.[[Value]]) otherwise.
    5. %直列形 ~SET { `Type^sl: `Error^l, `Name^sl: %名前, `Message^sl: %~message } ◎ Set serialized to { [[Type]]: "Error", [[Name]]: name, [[Message]]: message }.
    6. ~UAは、まだ仕様~化されていないが関心ng~data — 特に, `stack^jp ~propが挙げられる — が付帯しているならば、それを直列化した表現も %直列形 に添付するベキである ◎ User agents should attach a serialized representation of any interesting accompanying data which are not yet specified, notably the stack property, to serialized.

      この~dataを指定する進捗-中の作業については、 `Error Stacks^cite 提案 `JSERRORSTACKS$r を見よ。 ◎ See the Error Stacks proposal for in-progress work on specifying this data. [JSERRORSTACKS]

  18. ~ELIF[ %値 は `Array^jC ~exotic~objである ]: ◎ Otherwise, if value is an Array exotic object, then:

    1. %値~長さ記述子 ~LET ~ABRUPT `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.
  19. ~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.
  20. ~ELIF[ %値 は`~platform~obj$である ] ⇒ ~THROW `DataCloneError$E ◎ Otherwise, if value is a platform object, then throw a "DataCloneError" DOMException.
  21. ~ELIF[ `IsCallable$jA( %値 ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ Otherwise, if IsCallable(value) is true, then throw a "DataCloneError" DOMException.
  22. ~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.

  23. ~ELIF[ %値 は~exotic~objである ]~AND[ どの`~Realm$ %~realm に対しても[ %値 ~NEQ [ %~realm に結付けられている `Object.prototype$jI 内在的~obj ]]] ⇒ ~THROW `DataCloneError$E ◎ Otherwise, if value is an exotic object and value is not the %Object.prototype% intrinsic object associated with any JavaScript realm, then throw a "DataCloneError" DOMException.

    一例として、 `proxy^en ~obj。 【~JSの `Proxy^jC ~obj?】 ◎ For instance, a proxy object.

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

    注記: `Object.prototype$jI は、この段~以降を介して取扱われることになる。 その結果、その~exotic性は無視され,逆直列化の後には空な~objになる(それは、`変異-不能な~prototype~exotic~obj$ではない)。 ◎ %Object.prototype% will end up being handled via this step and subsequent steps. The end result is that its exoticness is ignored, and after deserialization the result will be an empty object (not an immutable prototype exotic object).

  25. %memory[ %値 ] `~SET$ %直列形 ◎ Set memory[value] to serialized.
  26. ~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 ~ABRUPT `StructuredSerializeInternal$jA( %~entry . `Key^sl, %~storage用, %memory ) ◎ Let serializedKey be ? StructuredSerializeInternal(entry.[[Key]], forStorage, memory).
        2. %直列形の値 ~LET ~ABRUPT `StructuredSerializeInternal$jA( %~entry . `Value^sl, %~storage用, %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 ~ABRUPT `StructuredSerializeInternal$jA( %~entry, %~storage用, %memory ) ◎ Let serializedEntry be ? StructuredSerializeInternal(entry, forStorage, memory).
        2. %直列形 . `SetData^sl に %直列形の~entry を`付加する$ ◎ Append serializedEntry to serialized.[[SetData]].
    3. ~ELIF[ %値 は`直列化-可能$な`~platform~obj$である ] ⇒ %値 の`首~interface$用の`直列化~手続き$( %値, %直列形, %~storage用 ) を遂行する ◎ Otherwise, if value is a platform object that is a serializable object, then perform the serialization steps for value's primary interface, given value, serialized, and forStorage.

      `直列化~手続き$は `下位-直列化@ を遂行することも必要になり得る。 これは、値 %下位-値 を入力にとり, `StructuredSerializeInternal$jA( %下位-値, %~storage用, %memory ) を返す演算である。 (言い換えれば、`下位-直列化$は,この呼出nの中に整合するよう特化された `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たち ~LET ~NOABRUPT `EnumerableOwnPropertyNames$jA( %値, `key^i【!%key】 ) ◎ for each key in ! EnumerableOwnPropertyNames(value, key):
      2. %~keyたち を成す ~EACH( %~key ) に対し: ◎ ↑

        1. ~IF[ ~NOABRUPT `HasOwnProperty$jA( %値, %~key ) ~EQ ~F ] ⇒ ~CONTINUE ◎ If ! HasOwnProperty(value, key) is true, then:
        2. %入力~値 ~LET ~ABRUPT %値 . `Get^sl( %~key, %値 ) ◎ Let inputValue be ? value.[[Get]](key, value).
        3. %出力~値 ~LET ~ABRUPT `StructuredSerializeInternal$jA( %入力~値, %~storage用, %memory ) ◎ Let outputValue be ? StructuredSerializeInternal(inputValue, forStorage, memory).
        4. %直列形 . `Properties^sl に { `Key^sl: %~key, `Value^sl: %出力~値 } を`付加する$ ◎ Append { [[Key]]: key, [[Value]]: outputValue } to serialized.[[Properties]].
  27. ~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.8.4. `StructuredSerialize^jA ( %値 )

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

2.8.5. `StructuredSerializeForStorage^jA ( %値 )

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

2.8.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 ⇒ %値 ~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]].
    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 ~ABRUPT `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 %直列形 . `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 . `Intrinsics^sl . `%Array.prototype%^sl ◎ Let outputProto be targetRealm.[[Intrinsics]].[[%Array.prototype%]].
      2. %値 ~SET ~NOABRUPT `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. ~ELIF[ %直列形 . `Type^sl ~EQ `Error^l ]: ◎ Otherwise, if serialized.[[Type]] is "Error", then:

      1. %~prototype ~LET %直列形 . `Name^sl に応じて ⇒# `EvalError^l ならば `EvalError.prototype$jI / `RangeError^l ならば `RangeError.prototype$jI / `ReferenceError^l ならば `ReferenceError.prototype$jI / `SyntaxError^l ならば `SyntaxError.prototype$jI / `TypeError^l ならば `TypeError.prototype$jI / `URIError^l ならば `URIError.prototype$jI / ~ELSE_ `Error.prototype$jI ◎ Let prototype be %Error.prototype%. ◎ If serialized.[[Name]] is "EvalError", then set prototype to %EvalError.prototype%. ◎ If serialized.[[Name]] is "RangeError", then set prototype to %RangeError.prototype%. ◎ If serialized.[[Name]] is "ReferenceError", then set prototype to %ReferenceError.prototype%. ◎ If serialized.[[Name]] is "SyntaxError", then set prototype to %SyntaxError.prototype%. ◎ If serialized.[[Name]] is "TypeError", then set prototype to %TypeError.prototype%. ◎ If serialized.[[Name]] is "URIError", then set prototype to %URIError.prototype%.

      2. %~message ~LET %直列形 . `Message^sl ◎ Let message be serialized.[[Message]].
      3. %値 ~SET ~NOABRUPT `ObjectCreate$jA( %~prototype, « `ErrorData^sl » ) ◎ Set value to ! ObjectCreate(prototype, « [[ErrorData]] »).
      4. %~message記述子 ~LET `~PropertyDescriptor$js{ `Value^sl: %~message, `Writable^sl: ~T, `Enumerable^sl: ~F, `Configurable^sl: ~T } ◎ Let messageDesc be PropertyDescriptor{ [[Value]]: message, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }.
      5. ~IF[ %~message ~NEQ `undefined^jv ] ⇒ ~NOABRUPT `OrdinaryDefineOwnProperty$jA( %値, `message^l, %~message記述子 ) ◎ If message is not undefined, then perform ! OrdinaryDefineOwnProperty(value, "message", messageDesc).
      6. 他にも %直列形 に添付された関心ng~dataがあるならば、それも逆直列化して %値 に添付するベキである ◎ Any interesting accompanying data attached to serialized should be deserialized and attached to value.
    16. その他: ◎ 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 ~ABRUPT `StructuredDeserialize$jA( %~entry . `Key^sl, %宛先~realm, %memory ) ◎ Let deserializedKey be ? StructuredDeserialize(entry.[[Key]], targetRealm, memory).
        2. %逆直列形の値 ~LET ~ABRUPT `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 ~ABRUPT `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 ~ABRUPT `StructuredDeserialize$jA( %~entry . `Value^sl, %宛先~realm, %memory ) ◎ Let deserializedValue be ? StructuredDeserialize(entry.[[Value]], targetRealm, memory).
        2. %結果 ~LET ~NOABRUPT `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 ) を返す演算である(言い換えれば、`下位-逆直列化$は,この呼出nの中で整合するよう特化された `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.8.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[ ~NOABRUPT `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 }.

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

  3. %直列形 ~LET ~ABRUPT `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[ ~NOABRUPT `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. ~ABRUPT `DetachArrayBuffer$jA( %転送対象 ) を遂行する ◎ Perform ? DetachArrayBuffer(transferable).

        注記: 仕様は、 `ArrayBuffer$I が切離されるのを防ぐためとして, `ArrayBufferDetachKey^sl 内部~slotを利用できる。 これは `WebAssembly JavaScript Interface^cite に利用される — 例えば `WASMJS$r 。 ◎ Specifications can use the [[ArrayBufferDetachKey]] internal slot to prevent ArrayBuffers from being detached. This is used in WebAssembly JavaScript Interface, for example. [WASMJS]

    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.8.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 ~ABRUPT `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.8.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な`直列化~手続き$がある場合、[ %~storage用 引数 ~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を生産する。 行先が複数ある状況では、転送ngはイミを成さないことに注意。 ◎ 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.


[ 作者~codeが~UA~methodの中へ~callした結果として同期的に呼出されてはいない所 ]から,抽象-演算[ `StructuredSerialize$jA / `StructuredSerializeForStorage$jA / `StructuredSerializeWithTransfer$jA ]を呼出すときは — それが任意の~objに対し遂行されている場合には — 呼出す前に,適正に[ `~scriptを走らすために準備する$, `~callbackを走らすために準備する$ ]よう~careするモノトスル。 このことは、必要とされる — 直列化~処理-は、その~~最終的な深い直列化~手続きの一部として,作者により定義される~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は,【~web】~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.