Skip to content

dslomov/ecmascript-structured-clone

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 

Repository files navigation

Structured cloning and transfer

Overview

Structured cloning algorithm defines the semantics of copying a well-defined subset of ECMAScript objects between Code Realms. This algorithm is extensible by host enviroment to support cloning of host objects.

Optionally, some kinds of objects may support a "transfer" operation, the effect of which is to transfer "ownership" of some resource associated with an object to a different Code Realm. The object then becomes unusable in the source Code Realm.


This specification combines and subsumes http://www.whatwg.org/specs/web-apps/current-work/#dom-messageport-postmessage and http://www.whatwg.org/specs/web-apps/current-work/#structured-clone as they really belong together.

HTML spec will be updated to refer to this specification of the StructuredClone algorithm.


We introduce a StructuredClone operator.

Transferable objects carry a [[Transfer]] internal data property that is either a transfer operator or "neutered", and an [[OnSuccessfulTransfer]] internal method.

Objects defined outside ECMAScript need to define a [[Clone]] internal method that returns a copy of the object.

Note: The first iteration is not user-pluggable. It is about moving the semantics into ECMAScript proper and tying them down.

StructuredClone(input, transferList, targetRealm)

The operator StructuredClone either returns a structured clone of input or throws an exception. A structured clone of an object input is an object in Code Realm targetRealm. transferList is a list of objects that should be transferred during cloning of input.

  1. Let memory be a map of source-to-destination object mappings.
  2. For each object transferable in transferList:
    1. If transferable does not have a [[Transfer]] internal data property whose value is an operator, throw a DataCloneError exception.
    2. Let transferResult be a result of a call to a transferable's internal method [[Transfer]] with argument targetRealm.
    3. ReturnIfAbrupt( transferResult )
    4. Append a mapping from transferable to transferResult to memory.
  3. Let clone be the result of InternalStructuredClone( input, memory, targetRealm ).
  4. ReturnIfAbrupt( clone ).
  5. For each object transferable in transferList:
    1. Let transferResult be a target of mapping from transferable in memory.
    2. Run transferable's internal method [[OnSuccessfulTransfer]](transferResult, targetRealm).
  6. Return clone.

InternalStructuredClone(input, memory, targetRealm)

The operator InternalStructuredClone either returns a structured clone of input in Code Realm targetRealm or throws an exception.

  1. If input is the source object of a pair of objects in memory, then return the destination object in that pair of objects.
  2. If input's [[Transfer]] is “neutered”, throw a DataCloneError exception.
  3. If input is a primitive value, return input.
  4. Let deepClone be false.
  5. If input has a [[BooleanData]] internal data property:
    • Let output be a new Boolean object in targetRealm whose [[BooleanData]] is [[BooleanData]] of input.
  6. If input has a [[NumberData]] internal data property:
    • Let output be a new Number object in targetRealm whose [[NumberData]] is [[NumberData]] of input.
  7. If input has a [[StringData]] internal data property:
    • Let output be a new String object in targetRealm whose [[StringData]] is [[StringData]] of input.
  8. If input has a [[DateValue]] internal data property:
    • Let output be a new Date object in targetRealm whose [[DateValue]] is [[DateValue]] of input.
  9. If input.[[RegExpMatcher]] exists:
    • Let output be new RegExp object r in targetRealm such that:
      • [[RegExpMatcher]] of r is [[RegExpMatcher]] of input.
      • [[OriginalSource]] of r is [[OriginalSource]] of input.
      • [[OriginalFlags]] of r is [[OriginalFlags]] of input.
  10. If input has [[ArrayBufferData]] internal data property:
    1. Set output to CopyArrayBufferToRealm(input, targetRealm).
  11. If input has [[ViewedArrayBuffer]] internal data property, then:
    1. let arrayBuffer be a value of input's [[ViewedArrayBuffer]] internal data property.
    2. let arrayBufferClone be InternalStructuredClone(arrayBuffer, memory, targetRealm)
    3. ReturnIfAbrupt(arrayBufferClone)
    4. if input instanceof %DataView% intrinsic object in current realm:
      1. Let output be an instance of %DataView% intrinsic object in targetRealm.
      2. Set output's [[ViewedArrayBuffer]] to arrayBufferClone.
      3. Set output's [[ByteOffset]] to input's [[ByteOffset]].
      4. Set output's [[ByteLength]] to input's [[ByteLength]].
    5. Otherwise, if input instanceof %TypedArray% for one of typed arrays' intrinsics TypedArray in current code realm:
      1. Let output be an instance of %TypedArray% intrinsic object in targetRealm.
      2. Set output's [[ByteOffset]] to input's [[ByteOffset]].
      3. Set output's [[ByteLength]] to input's [[ByteLength]].
      4. Set output's [[ArrayLength]] to input's [[ArrayLength]].
  12. If input has [[MapData]] internal data property, ...
  13. If input has [[SetData]] internal data property, ...
  14. If input is an exotic Array object:
    1. Let output be a new Array in targetRealm.
    2. Set output.length to input.length.
    3. Set deepClone to true.
  15. Otherwise, if IsCallable( input), throw a DataCloneError exception.
  16. Otherwise, if input has [[ErrorData]] propety, throw a DataCloneError exception.
  17. Otherwise, if input has [[Clone]] internal method:
    1. Set output to a result of input.[[Clone]]( targetRealm )
  18. Otherwise, if input is an exotic object, throw a DataCloneError exception.
  19. Otherwise:
    1. Let object be a new Object in targetRealm.
    2. set deepClone to true.
  20. Add a mapping from input (the source object) to output (the destination object) to memory.
  21. If deepClone is true:
    1. Let keys be input.[[OwnPropertyKeys]]().
    2. For each key in keys:
      1. If key is a primitive String value, set outputKey to key
      2. TODO: Symbols
      3. Let sourceValue be a result of a call to input's internal method [[Get]]( key, input).
      4. ReturnIfAbrupt( sourceValue).
      5. Let clonedValue be InternalStructuredClone( sourceValue, memory).
      6. ReturnIfAbrupt( clonedValue).
      7. Let outputSet be a result of a call to output's internal method [[Set]]( outputKey, clonedValue, output).
      8. ReturnIfAbrupt( outputSet )
  22. Return output.

Definition of [[Transfer]](targetRealm) on ECMAScript exotic objects.

Definition of object.[[Transfer]]( targetRealm ):

  1. If object has an [[ArrayBufferData]] internal data property then:
  2. Return CopyArrayBufferToRealm(object, targetRealm).

Definition of CopyArrayBufferToRealm(arrayBuffer, targetRealm)

  1. Let result be a new ArrayBuffer arrayBuffer in targetRealm.
  2. Let length be a value of arrayBuffer's [[ArrayBufferByteLength]] internal slot.
  3. Let srcBlock be the value of arrayBuffer's [[ArrayBufferData]] internal slot.
  4. Let setStatus be a result of SetArrayBufferData(result,length).
  5. ReturnIfAbrupt(setStatus).
  6. Let targetBlock be a value of result's [[ArrayBufferData]] internal slot.
  7. Perform CopyDataBlock(targetBlock, 0, srcBlock, 0, length).
  8. Return result.

Definition of [[OnSuccessfulTransfer]]() on ECMAScript exotic objects.

Definition of internal method object.[[OnSuccessfulTransfer]]( transferResult, targetRealm ):

  1. If object has an [[ArrayBufferData]] internal data property then:
    1. Let neuteringResult be SetArrayBufferData( object, 0 ).
    2. ReturnIfAbrupt( neuteringResult ).
    3. Set value of object's [[Transfer]] internal data property to "neutered".

DataCloneError error object

Indicates failure of the structured clone algorithm.

{Rationale: typically, ECMAScript operations throw RangeError for similar failures, but we need to preserve DOM compatibnility}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published