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

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

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

2.7.1. ~cloneable~obj

`~cloneable~obj$は、`~event-loop$間をまたぐ~cloningを~supportする~objである。 すなわち,それらは、異なる`生成元$に属する文書~間も含め,文書や~workerの境界を越えて~cloneし得る。 ~objには`~cloneable$でないものもある。 `~cloneable$であっても,そのすべての側面が~clone時に保全されるとは限らない。 ◎ Cloneable objects support being cloned across event loops. That is, they support being cloned across document and worker boundaries, including across documents of different origins. Not all objects are cloneable objects and not all aspects of objects that are cloneable objects are necessarily preserved when cloned.

`~platform~obj$は、次の内部~methodを持つ: ◎ Platform objects have the following internal method:

  • `Clone@sl( %宛先~Realm, %memory )

他から指定されない限り、 `Clone$sl() 内部~methodが呼出されたときは, `DataCloneError$E 例外を投出し~MUST(すなわち,既定においては、`~cloneable$でない)。 ◎ Unless specified otherwise, invoking the [[Clone]]() internal method must throw a "DataCloneError" DOMException. (By default, platform objects are not cloneable objects.)

【 %宛先~Realm は、おそらく,`~realm実行文脈$の~realmを意図している。 】

`~cloneable$である`~platform~obj$の `Clone$sl() 内部~methodは、ある手続きを走らすものと指定される。 この手続きは、例外を投出するか,または[ %宛先~Realm 内にて作成される, ~this の~clone ]を返さ~MUST。 ~cloningが何を意味するかは、当の~obj自身の定義に委ねられる。 ◎ Platform objects that are cloneable objects have a [[Clone]]() internal method which is specified to run a series of steps. The result of running those steps must be a thrown exception or a clone of this, created in targetRealm. It is up such objects to define what cloning means for them.

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

2.7.2. 転送可能な~obj

`転送可能な~obj$は、`~event-loop$間をまたぐ転送を~supportする。 転送は、実質的に,~objを再度~作成することである — その下層の~dataへの参照は共有しつつ,転送されている~objは~detachするような。 これは、高価な資源の所有権を転送するときに,有用になる。 ~objには`転送可能$でないものもある。 ~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.

転送は、不可逆であり,`転送する側にとっては^tnote冪等でない演算である。 ~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$は、次のものを持つ:

  • `Detached@sl 内部~slot
  • `Transfer@sl( %宛先~Realm ) 内部~method
◎ Platform objects that are transferable objects have a [[Detached]] internal slot and the following internal method: ◎ [[Transfer]] ( targetRealm )

すべての`~platform~obj$は `Clone$sl() 内部~methodを持つが,[ `Detached$sl 内部~slot / `Transfer$sl() 内部~method ]を持つとは限らない。 ◎ Whereas all platform objects have a [[Clone]]() internal method, not all have a [[Detached]] internal slot and a [[Transfer]]() internal method.

`転送可能$である`~platform~obj$の `Transfer$sl() 内部~methodは、次のように定義され~MUST:

  • 例外を投出するか, または %宛先~Realm 内にて作成される, ~this の~cloneを返す。
  • 返り値は ~this の下層の~dataを共有する。
  • ~this.`Detached$sl を ~T に設定する。

~objの転送が何を意味するかは、当の~obj自身の定義に委ねられる。

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

~JS仕様にて定義される~objは、 `StructuredCloneWithTransfer$jA 抽象演算により直接的に取扱われる(~~精確には, `IsTransferable$jA, `Transfer$jA により)。 ◎ Objects defined in the JavaScript specification are handled by the StructuredCloneWithTransfer abstract operation directly. (Technically, by IsTransferable and Transfer.)

2.7.3. `StructuredCloneWithTransfer^jA( %入力, %転送-~list, %宛先~Realm )

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

    `StructuredClone$jA 抽象演算における %memory ~mapの目的0は、~objが重ねて~cloneされないようにすることである。 これには、循環参照を保全して,~graphにおける~objの重複を識別することが必要になる。 ◎ The purpose of the memory map, both here and in the StructuredClone abstract operation, is to avoid cloning objects twice. This ends up preserving cycles and the identity of duplicate objects in graphs.

  2. ~FOR %転送-~list 内の~EACH ( ~obj %転送対象 ) に対し: ◎ For each object transferable in transferList:

    1. ~IF[ `IsTransferable$jA( %転送対象 ) ~EQ ~F ] ⇒ ~THROW `DataCloneError$E ◎ If IsTransferable(transferable) is false, then throw a "DataCloneError" DOMException.
    2. %仮置場 ~LET ~UAにより定義される 仮置場( placeholder ) ~obj ◎ Let placeholder be a user-agent-defined placeholder object.
    3. %memory 内に,新たな~entry ( %転送対象 → %仮置場 ) を作成する ◎ Create an entry in memory with key transferable and value placeholder.
  3. %~clone ~LET ? `StructuredClone$jA( %入力, %宛先~Realm, %memory ) ◎ Let clone be the result of ? StructuredClone(input, targetRealm, memory).
  4. %出力~転送-~list ~LET 新たな空 `List$js ◎ Let outputTransferList be a new empty List.
  5. ~FOR %転送-~list 内の~EACH ( ~obj %転送対象 ) に対し: ◎ For each object transferable in transferList:

    1. %仮置場~結果 ~LET %memory [ %転送対象 ] ◎ Let placeholderResult be the value of the entry in memory whose key is transferable.
    2. %転送-結果 ~LET ? `Transfer$jA( %転送対象, %宛先~Realm ) ◎ Let transferResult be ? Transfer(transferable, targetRealm).
    3. %~clone の中で、 %仮置場~結果 への参照を %転送-結果 で置換する — %仮置場~結果 への参照を保持している あらゆるものは、 %転送-結果 への参照を保持させるように。 ◎ Within clone, replace references to placeholderResult with transferResult, such that everything holding a reference to placeholderResult, now holds a reference to transferResult.

      これは、~JSに規定されていない,通例でない低levelの演算である。 ◎ This is a rather unusual low-level operation for which no primitives are defined by JavaScript.

    4. %出力~転送-~list の末尾に %転送-結果 を追加する ◎ Add transferResult as the last element of outputTransferList.
  6. ~RET { `Clone^sl: %~clone, `TransferList^sl: %出力~転送-~list } ◎ Return { [[Clone]]: clone, [[TransferList]]: outputTransferList }.

`StructuredCloneWithTransfer$jA / `StructuredClone$jA 抽象演算は、元々は,[ “有構造~clone”, “内部~有構造~clone” ]~algoとして知られていた。 ~objの転送は、今や `StructuredCloneWithTransfer$jA 抽象演算により取扱われる — それは、以前までは[ `Window.postMessage()$m, `MessagePort.postMessage()$m ]~methodの~algoの一部により取扱われていたものである。 ◎ Originally the StructuredCloneWithTransfer abstract operation was known as the "structured clone" algorithm. The StructuredClone abstract operation was known as the "internal structured clone" algorithm. Transferring objects, now handled by the StructuredCloneWithTransfer abstract operation, were formerly handled by parts of the algorithm of the postMessage() method on the Window object and the postMessage() method on the MessagePort object.

2.7.4. `StructuredClone^jA( %入力, %宛先~Realm [ , %memory ] )

  1. ~IF[ %memory は与えられていない ] ⇒ %memory ~LET 空`~map$ ◎ If memory was not supplied, let memory be an empty map.
  2. ~IF[ %memory [ %入力 ] ~NEQ ε ] ⇒ ~RET %memory [ %入力 ] ◎ If memory contains an entry with key input, then return that entry's value.
  3. ~IF[ `Type$jA( %入力 ) ~IN { `Undefined^jC, `Null^jC, `Boolean^jC, `String^jC, `Number^jC } ] ⇒ ~RET %入力 ◎ If Type(input) is Undefined, Null, Boolean, String, or Number, then return input.
  4. ~IF[ `Type$jA( %入力 ) ~EQ `Symbol^jC ] ⇒ ~THROW `DataCloneError$E ◎ If Type(input) is Symbol, then throw a "DataCloneError" DOMException.
  5. %~deep~clone ~LET ~F;
    %出力 ~LET ε ◎ Let deepClone be false.
  6. ~IF[ %入力.`BooleanData^sl ~NEQ ε ] ⇒ %出力 ~SET 次のようにされた, %宛先~Realm 内の新たな `Boolean^jC ~obj ⇒ .`BooleanData^sl ~SET %入力.`BooleanData^sl ◎ If input has a [[BooleanData]] internal slot, then let output be a new Boolean object in targetRealm whose [[BooleanData]] internal slot value is the [[BooleanData]] internal slot value of input.
  7. ~ELIF[ %入力.`NumberData^sl ~NEQ ε ] ⇒ %出力 ~SET 次のようにされた, %宛先~Realm 内の新たな `Number^jC ~obj ⇒ .`NumberData^sl ~SET %入力.`NumberData^sl ◎ Otherwise, if input has a [[NumberData]] internal slot, then let output be a new Number object in targetRealm whose [[NumberData]] internal slot value is the [[NumberData]] internal slot value of input.
  8. ~ELIF[ %入力.`StringData^sl ~NEQ ε ] ⇒ %出力 ~SET 次のようにされた, %宛先~Realm 内の新たな `String^jC ~obj ⇒ .`StringData^sl ~SET %入力.`StringData^sl ◎ Otherwise, if input has a [[StringData]] internal slot, then let output be a new String object in targetRealm whose [[StringData]] internal slot value is the [[StringData]] internal slot value of input.
  9. ~ELIF[ %入力.`DateValue^sl ~NEQ ε ] ⇒ %出力 ~SET 次のようにされた, %宛先~Realm 内の新たな `Date^jC ~obj ⇒ .`DateValue^sl ~SET %入力.`DateValue^sl ◎ Otherwise, if input has a [[DateValue]] internal slot, then let output be a new Date object in targetRealm whose [[DateValue]] internal slot value is the [[DateValue]] internal slot value of input.
  10. ~ELIF[ %入力.`RegExpMatcher^sl ~NEQ ε ] ⇒ %出力 ~SET 次のようにされた, %宛先~Realm 内の新たな `RegExp^jC ~obj ⇒ .`RegExpMatcher^sl ~SET %入力.`RegExpMatcher^sl;
    .`OriginalSource^sl ~SET %入力.`OriginalSource^sl;
    .`OriginalFlags^sl ~SET %入力.`OriginalFlags^sl;
    ◎ Otherwise, if input has a [[RegExpMatcher]] internal slot, then let output be a new RegExp object in targetRealm whose [[RegExpMatcher]] internal slot value is the [[RegExpMatcher]] internal slot value of input, whose [[OriginalSource]] internal slot value is the [[OriginalSource]] internal slot value of input, and whose whose [[OriginalFlags]] internal slot value is the [[OriginalFlags]] internal slot value of input.
  11. ~ELIF[ %入力.`ArrayBufferData^sl ~NEQ ε ]: ◎ Otherwise, if input has an [[ArrayBufferData]] internal slot, then:

    1. ~IF[ `IsDetachedBuffer$jA( %入力 ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ If IsDetachedBuffer(input) is true, then throw a "DataCloneError" DOMException.
    2. %出力~配列~buffer ~LET %宛先~Realm 内の `ArrayBuffer$jI ~intrinsic~obj ◎ Let outputArrayBuffer be the %ArrayBuffer% intrinsic object in targetRealm.
    3. %出力 ~SET ? `CloneArrayBuffer$jA( %入力, `0^jV, %出力~配列~buffer ) ◎ Let output be ? CloneArrayBuffer(input, 0, outputArrayBuffer).
  12. ~ELIF[ %入力.`ViewedArrayBuffer^sl ~NEQ ε ]: ◎ Otherwise, if input has a [[ViewedArrayBuffer]] internal slot, then:

    1. %~buffer ~LET %入力.`ViewedArrayBuffer^sl ◎ Let buffer be the value of input's [[ViewedArrayBuffer]] internal slot.
    2. %~buffer~clone ~LET ? `StructuredClone$jA( %~buffer, %宛先~Realm, %memory ) ◎ Let bufferClone be ? StructuredClone(buffer, targetRealm, memory).
    3. ~IF[ %入力.`DataView^sl ~NEQ ε ] ⇒ %出力 ~SET 次のようにされた, %宛先~Realm 内の新たな `DataView^jC ~obj ⇒ .`DataView^sl ~SET ~T;
      .`ViewedArrayBuffer^sl ~SET %~buffer~clone;
      .`ByteLength^sl ~SET %入力.`ByteLength^sl;
      .`ByteOffset^sl ~SET %入力.`ByteOffset^sl ◎ If input has a [[DataView]] internal slot, then let output be a new DataView object in targetRealm whose [[DataView]] internal slot value is true, whose [[ViewedArrayBuffer]] internal slot value is bufferClone, whose [[ByteLength]] internal slot value is the [[ByteLength]] internal slot value of input, and whose [[ByteOffset]] internal slot value is the [[ByteOffset]] internal slot value of input.
    4. ~ELSE: ◎ Otherwise:

      1. ~Assert: %入力.`TypedArrayName^sl ~NEQ ε ◎ Assert: input has a [[TypedArrayName]] internal slot.
      2. %構築子 ~LET %入力.`TypedArrayName^sl に対し[ TypedArray Constructors table の一列目 ]に挙げられている, %宛先~Realm 内の~intrinsic~obj ◎ Let constructor be the intrinsic object listed in column one of The TypedArray Constructors table for the value of input's [[TypedArrayName]] internal slot in targetRealm.
      3. %byteOffset ~LET %入力.`ByteOffset^sl ◎ Let byteOffset be input's [[ByteOffset]] internal slot value.
      4. %長th ~LET %入力.`ArrayLength^sl ◎ Let length be input's [[ArrayLength]] internal slot value.
      5. %出力 ~SET ? `TypedArrayCreate$jA( %構築子, «%~buffer~clone, %byteOffset, %長th» ) ◎ Let output be ? TypedArrayCreate(constructor, « bufferClone, byteOffset, length »).
  13. ~ELIF[ %入力.`MapData^sl ~NEQ ε ]: ◎ Otherwise, if input has [[MapData]] internal slot, then:

    1. %出力 ~SET 次のようにされた, %宛先~Realm 内の新たな `Map^jC ~obj ⇒ .`MapData^sl ~SET 新たな空 `List$js ◎ Let output be a new Map object in targetRealm whose [[MapData]] internal slot value is a new empty List.
    2. %~deep~clone ~SET ~T ◎ Set deepClone to true.
  14. ~ELIF[ %入力.`SetData^sl ~NEQ ε ]: ◎ Otherwise, if input has [[SetData]] internal slot, then:

    1. %出力 ~SET 次のようにされた, %宛先~Realm 内の新たな `Set^jC ~obj ⇒ .`SetData^sl ~SET 新たな空 `List$js ◎ Let output be a new Set object in targetRealm whose [[SetData]] internal slot value is a new empty List.
    2. %~deep~clone ~SET ~T ◎ Set deepClone to true.
  15. ~ELIF[ %入力 は `Array^jC ~exotic~objである ]: ◎ Otherwise, if input is an Array exotic object, then:

    1. %入力~長th ~LET `OrdinaryGetOwnProperty$jA( %入力, `length^l ).`Value^sl ◎ Let inputLen be OrdinaryGetOwnProperty(input, "length").[[Value]].
    2. %出力~prototype ~LET %宛先~Realm 内の `ArrayPrototype$jI ~intrinsic~obj ◎ Let outputProto be the %ArrayPrototype% intrinsic object in targetRealm.
    3. %出力 ~SET ! `ArrayCreate$jA( %入力~長th, %出力~prototype ) ◎ Let output be ! ArrayCreate(inputLen, outputProto).
    4. %~deep~clone ~SET ~T ◎ Set deepClone to true.
  16. ~ELIF[ %入力.`Clone$sl ~NEQ ε ] ⇒ %出力 ~SET ? %入力 .`Clone$sl( %宛先~Realm, %memory ) ◎ Otherwise, if input has a [[Clone]]() internal method, then let output be ? input.[[Clone]](targetRealm, memory).
  17. ~ELIF[ `IsCallable$jA( %入力 ) ~EQ ~T ] ⇒ ~THROW `DataCloneError$E ◎ Otherwise, if IsCallable(input) is true, then throw a "DataCloneError" DOMException.
  18. ~ELIF[ %入力 は[ .`Prototype^sl, .`Extensible^sl ]以外の内部~slotを持つ ] ⇒ ~THROW `DataCloneError$E ◎ Otherwise, if input 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.

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

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

  20. ~ELSE: ◎ Otherwise:

    1. %出力 ~SET %宛先~Realm 内の新たな `Object^jC ◎ Let output be a new Object in targetRealm.
    2. %~deep~clone ~SET ~T ◎ Set deepClone to true.
  21. %memory 内に,新たな~entry ( %入力 → %出力 ) を作成する ◎ Create an entry in memory whose key is input and value is output.
  22. ~IF[ %~deep~clone ~EQ ~F ] ⇒ ~RET %出力 ◎ If deepClone is true, then:
  23. ~IF[ %入力.`MapData^sl ~NEQ ε ] ⇒ ◎ If input has a [[MapData]] internal slot, then:

    1. %入力~list ~LET %入力.`MapData^sl ◎ Let inputList the value of input's [[MapData]] internal slot.
    2. %複製済~list ~LET 新たな空 `List$js ◎ Let copiedList be a new empty List.
    3. ~FOR %入力~list 内の ~EACH ( `Record$js {`Key^sl, `Value^sl} %~entry ) に対し: ◎ Repeat for each Record {[[Key]], [[Value]]} entry that is an element of inputList,

      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 は空でない ] ⇒ %複製済~list の末尾に %複製済~entry を~~追加する ◎ If copiedEntry.[[Key]] is not empty, append copiedEntry as the last element of copiedList.
    4. %出力~list ~LET %出力.`MapData^sl ◎ Let outputList be the value of output's [[MapData]] internal slot.
    5. ~FOR %複製済~list 内の ~EACH ( `Record$js {`Key^sl, `Value^sl} %~entry ) に対し: ◎ For each Record {[[Key]], [[Value]]} entry that is an element of copiedList,

      1. %出力~key ~LET ? `StructuredClone$jA( %~entry.`Key^sl, %宛先~Realm, %memory ) ◎ Let outputKey be ? StructuredClone(entry.[[Key]], targetRealm, memory).
      2. %出力~値 ~LET ? `StructuredClone$jA( %~entry.`Value^sl, %宛先~Realm, %memory ) ◎ Let outputValue be ? StructuredClone(entry.[[Value]], targetRealm, memory).
      3. %出力~list の末尾に { `Key^sl: %出力~key, `Value^sl: %出力~値 } を追加する ◎ Add { [[Key]]: outputKey, [[Value]]: outputValue } as the last element of outputList.
  24. ~ELIF[ %入力.`SetData^sl ~NEQ ε ] ⇒ ◎ Otherwise, if input has a [[SetData]] internal slot, then:

    1. %複製済~list ~LET %入力.`SetData^sl の複製 ◎ Let copiedList be a copy of the value of input's [[SetData]] internal slot.
    2. %出力~list ~LET %出力.`SetData^sl ◎ Let outputList be the value of output's [[SetData]] internal slot.
    3. ~FOR %複製済~list 内の空でない ~EACH ( %~entry ) に対し: ◎ For each entry that is an element of copiedList that is not empty,

      1. %出力~entry ~LET ? `StructuredClone$jA( %~entry, %宛先~Realm, %memory ) ◎ Let outputEntry be ? StructuredClone(entry, targetResult, memory).
      2. %出力~list の末尾に %出力~entry を追加する ◎ Add outputEntry as the last element of outputList.
  25. ~ELSE: ◎ Otherwise:

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

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

        1. %入力~記述子 ~LET ! %入力.`GetOwnProperty^sl( %~key ) ◎ Let inputDesc be ! input.[[GetOwnProperty]](key).
        2. ~IF[ %入力~記述子.`Enumerable^sl ~EQ ~T ] ⇒ %可列挙~key~list の末尾に %~key を追加する ◎ If inputDesc.[[Enumerable]] is true, then add key as the last element of enumerableKeys.
      2. %可列挙~key~list 内の~EACH( %~key ) に対し: ◎ For each key in enumerableKeys:

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

          1. %入力~値 ~LET ? %入力.`Get^sl( %~key, %入力 ) ◎ Let inputValue be ? input.[[Get]](key, input).
          2. %出力~値 ~LET ? `StructuredClone$jA( %入力~値, %宛先~Realm, %memory ) ◎ Let outputValue be ? StructuredClone(inputValue, targetRealm, memory).
          3. ? `CreateDataProperty$jA( %出力, %~key, %出力~値 ) を遂行する ◎ Perform ? CreateDataProperty(output, key, outputValue).

      注記: 上で遂行される~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 output.

一般に実装は、 %宛先~Realm における~objの作成を実装するために,何らかの類の直列化と `marshalling$x を利用する必要がある — %宛先~Realm は,異なる`~event-loop$内にあって、[ `StructuredCloneWithTransfer$jA / `StructuredClone$jA ]を呼出す~codeからは容易に~access可能でないかもしれないので。 ◎ In general implementations will need to use some kind of serialization and marshalling to implement the creation of objects in targetRealm, as targetRealm could be in a different event loop and not easily accessible to the code that invokes StructuredCloneWithTransfer or StructuredClone.

2.7.5. `IsTransferable^jA( %O )

  1. ~Assert: `Type$jA( %O ) ~EQ `Object^jC ◎ Assert: Type(O) is Object.
  2. ~IF[ %O.`ArrayBufferData^sl ~NEQ ε ]: ◎ If O has an [[ArrayBufferData]] internal slot, then:

    1. ~IF[ `IsDetachedBuffer$jA( %O ) ~EQ ~T ] ⇒ ~RET ~F ◎ If IsDetachedBuffer(O) is true, then return false.
    2. ~RET ~T ◎ Return true.
  3. ~ELIF[ %O.`Detached$sl ~NEQ ε ]: ◎ Otherwise, if O has a [[Detached]] internal slot, then:

    1. ~IF[ %O.`Detached$sl ~EQ ~T ] ⇒ ~RET ~F ◎ If O's [[Detached]] internal slot value is true, then return false.
    2. ~RET ~T ◎ Return true.
  4. ~RET ~F ◎ Return false.

2.7.6. `Transfer^jA( %入力, %宛先~Realm )

  1. ~IF[ %入力.`ArrayBufferData^sl ~NEQ ε ]: ◎ If input has an [[ArrayBufferData]] internal slot, then:

    1. %出力 ~LET 次のようにされた, %宛先~Realm 内の新たな `ArrayBuffer^jC ~obj ⇒ .`ArrayBufferByteLength^sl ~SET %入力.`ArrayBufferByteLength^sl;
      .`ArrayBufferData^sl ~SET %入力.`ArrayBufferData^sl ◎ Let output be a new ArrayBuffer object in targetRealm whose [[ArrayBufferByteLength]] internal slot value is the [[ArrayBufferByteLength]] internal slot value of input, and whose [[ArrayBufferData]] internal slot value is the [[ArrayBufferData]] internal slot value of input.
    2. ! `DetachArrayBuffer$jA( %入力 ) を遂行する ◎ Perform ! DetachArrayBuffer(input).
    3. ~RET %出力 ◎ Return output.
  2. ~RET ? %入力.`Transfer$sl( %宛先~Realm ) ◎ Return ? input.[[Transfer]](targetRealm).

2.7.7. 他の仕様から有構造~cloneを遂行するとき

他の仕様は[ `StructuredClone$jA, `StructuredCloneWithTransfer$jA, `IsTransferable$jA, `Transfer$jA ]抽象演算を利用してよい。 ◎ Other specifications may use the StructuredClone, StructuredCloneWithTransfer, IsTransferable, and Transfer abstract operations.

一般に、~callする側は,~JS値の代わりに~WebIDL値を渡してもよい — これは、これらの~algoを呼出す前に,暗黙的な`~JS値への変換$xを遂行するものと解される。 ◎ In general, call sites may pass in Web IDL values instead of JavaScript values; this is to be understood to perform an implicit conversion to the JavaScript value before invoking these algorithms.

~callする側が[ 作者~codeが~UA~methodの中へ~callした結果として同期的に呼出されてはいない ]場合、それが任意の~obj上で遂行されている場合には,これらの抽象演算を呼出す前に,適正に[ `~scriptを走らすために準備する$ / `~callbackを走らすために準備する$ ]よう~careし~MUST。 このことは、必要とされる — `StructuredClone$jA 演算は、その~~最終的な~deep~cloning手続きの一部として,作者により定義される~accessorを呼出すこともあり、その~accessorは[[ `~entry〜$/`~incumbent〜$ の概念が 適正に設定してある ]ことに依拠するような演算 ]の中へ~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 these abstract operations, if they are being performed on arbitrary objects. This is necessary because the StructuredClone operation can invoke author-defined accessors as part of its final deep-cloning steps, and these accessors could call into operations that rely on the entry and incumbent concepts being properly set up.

`postMessage()$m は、その引数に対し `StructuredCloneWithTransfer$jA を遂行するが、注意深く,その~algoの同期的~部位の内側で即時にそうする。 したがって、[ `~scriptを走らすために準備する$ / `~callbackを走らすために準備する$ ]必要なく,有構造~cloning~algoを利用できる。 ◎ postMessage performs StructuredCloneWithTransfer on its arguments, but is careful to do so immediately, inside the synchronous portion of its algorithm. Thus it is able to use the structured cloning algorithms without needing to prepare to run script and prepare to run a callback.

`~URLの構文解析$xは、作者~codeと同期的でない種々の時点で生じ得る。 しかしながら、~URL構文解析器が `StructuredClone$jA を適用するのは `Blob$I ~objのみなので、作者~codeを不正な[ `~entry〜$ / `~incumbent〜$ ]値で走らすのは危険でない。 よって,それについても、これらの準備~手続きを遂行する必要はない。 ◎ Parsing URLs can happen at a variety of times that are not the synchronous result of author code. However, the URL parser only applies StructuredClone to Blob objects, so it is not in danger of running author code with incorrect entry and incumbent values, and thus it too does not need to perform these preparation steps.

対照的に、 `StructuredClone$jA を利用して,[ 作者から供された何らかの~objを,`~event-loop$上の`~task$から直接的に 毎回~直列化する ]ような ~APIがあるとするなら、それは[ 有構造~clone~algoの中へ~callする前に適切な準備が遂行される ]ことを確保する必要がある。 現時点では、~platform上に そのような~APIはないことが知られている — 通例的には, `postMessage()$m の様に、作者~codeに同期して,事前に~cloneを遂行しておく方が単純になる。 ◎ In contrast, a hypothetical API that used StructuredClone to serialize some author-supplied object periodically, directly from a task on the event loop, would need to ensure it performs the appropriate preparations before calling into the structured clone algorithms. As of this time, we know of no such APIs on the platform; usually it is simpler to perform the clone ahead of time, as a synchronous consequence of author code, like postMessage.

2.7.8. `Blob^I / `FileList^I ~objに対する monkey patch

課題: この monkey patch は、そのうち除去されることになる。 w3c/FileAPI issue 32 を見よ。 ◎ This monkey patch will be removed in due course. See w3c/FileAPI issue 32.

`Blob$I ~objは、`~cloneable~obj$である。 ◎ Blob objects are cloneable objects.

各 `Blob$I ~objの内部~method `Clone$sl( %宛先~Realm, %memory ) は、次を走らせ~MUST( %memory は無視される): ◎ Each Blob object's [[Clone]](targetRealm, memory) internal method must run these steps:

  1. ~IF[ ~this はすでに`~closeされ$ている ] ⇒ ~THROW `DataCloneError$E ◎ If this is closed, then throw a "DataCloneError" DOMException.
  2. ~RET 同じ下層の~dataに対応するような, %宛先~Realm における ~this の新たな~instance ◎ Return a new instance of this in targetRealm, corresponding to the same underlying data.

`FileList$I ~objは`~cloneable~obj$である。 ◎ FileList objects are cloneable objects.

各 `FileList$I ~objの内部~method `Clone$sl( %宛先~Realm, %memory ) は、次を走らせ~MUST: ◎ Each FileList object's [[Clone]](targetRealm, memory) internal method must run these steps:

  1. %出力 ~LET %宛先~Realm 内の新たな `FileList$I ~obj ◎ Let output be a new FileList object in targetRealm.
  2. ~FOR ~this 内の~EACH ( %file ) に対し: ⇒ %出力 の[ `File$I ~objの~list ]の末尾に[ ? `StructuredClone$jA( %file, %宛先~Realm, %memory ) ]を追加する ◎ For each file in this, add ? StructuredClone(file, targetRealm, memory) to the end of the list of File objects of output.
  3. ~RET %出力 ◎ Return output.