Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 147 additions & 14 deletions document/js-api/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT
text: NativeError Object Structure; url: sec-nativeerror-object-structure
text: 𝔽; url: #𝔽
text: ℤ; url: #ℤ
text: SameValue; url: sec-samevalue
urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: dfn
url: valid/modules.html#valid-module
text: valid
Expand Down Expand Up @@ -101,6 +102,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
text: memory address; url: exec/runtime.html#syntax-memaddr
text: global address; url: exec/runtime.html#syntax-globaladdr
text: extern address; url: exec/runtime.html#syntax-externaddr
text: page size; url: exec/runtime.html#page-size
url: syntax/types.html#syntax-numtype
text: i32
text: i64
Expand Down Expand Up @@ -147,6 +149,11 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
urlPrefix: https://heycam.github.io/webidl/; spec: WebIDL
type: dfn
text: create a namespace object; url: create-a-namespace-object
urlPrefix: https://tc39.es/proposal-resizablearraybuffer/; spec: ResizableArrayBuffer proposal
type: dfn
text: IsFixedLengthArrayBuffer; url: sec-isfixedarraybuffer
text: HostResizeArrayBuffer; url: sec-hostresizearraybuffer
text: HostGrowSharedArrayBuffer; url: sec-hostgrowsharedarraybuffer
</pre>

<pre class='link-defaults'>
Expand Down Expand Up @@ -595,6 +602,8 @@ dictionary MemoryDescriptor {
interface Memory {
constructor(MemoryDescriptor descriptor);
unsigned long grow([EnforceRange] unsigned long delta);
ArrayBuffer toFixedLengthBuffer();
ArrayBuffer toResizableBuffer();
readonly attribute (ArrayBuffer or SharedArrayBuffer) buffer;
};
</pre>
Expand All @@ -607,14 +616,44 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
* \[[BufferObject]] : an {{ArrayBuffer}} or {{SharedArrayBuffer}} whose [=Data Block=] is [=identified with=] the above memory address

<div algorithm>
To <dfn>create a memory buffer</dfn> from a [=memory address=] |memaddr|, perform the following steps:
To <dfn>create a fixed length memory buffer</dfn> from a [=memory address=] |memaddr|, perform the following steps:

1. Let |block| be a [=Data Block=] which is [=identified with=] the underlying memory of |memaddr|.
1. If |block| is a [=Shared Data Block=],
1. Let |buffer| be a new {{SharedArrayBuffer}} with the internal slots \[[ArrayBufferData]] and \[[ArrayBufferByteLength]].
1. Set |buffer|.\[[ArrayBufferData]] to |block|.
1. Set |buffer|.\[[ArrayBufferByteLength]] to the length of |block|.
1. Perform ! [$SetIntegrityLevel$](|buffer|, `"frozen"`).
1. Otherwise,
1. Let |buffer| be a new {{ArrayBuffer}} with the internal slots \[[ArrayBufferData]], \[[ArrayBufferByteLength]], and \[[ArrayBufferDetachKey]].
1. Set |buffer|.\[[ArrayBufferData]] to |block|.
1. Set |buffer|.\[[ArrayBufferByteLength]] to the length of |block|.
1. Set |buffer|.\[[ArrayBufferDetachKey]] to "WebAssembly.Memory".
1. Return |buffer|.
</div>

Note: (TODO) Check whether only SharedArrayBuffers need integrity level "frozen" (see the Threads Proposal Overview).

To create a resizable memory buffer we perform the same steps as above, but also setting the buffer's maximum size.

<div algorithm>
To <dfn>create a resizable memory buffer</dfn> from a [=memory address=] |memaddr| and a |maxsize|, perform the following steps:

1. Let |block| be a [=Data Block=] which is [=identified with=] the underlying memory of |memaddr|.
1. Let |length| be the length of |block|.
1. If |maxsize| &gt; (65536 &times; 65536),
1. Throw a {{RangeError}} exception.
1. If |block| is a [=Shared Data Block=],
1. Let |buffer| be a new {{SharedArrayBuffer}} whose \[[ArrayBufferData]] is |block| and \[[ArrayBufferByteLength]] is set to the length of |block|.
1. Let |buffer| be a new {{SharedArrayBuffer}} with the internal slots \[[ArrayBufferData]], \[[ArrayBufferByteLength]], and \[[ArrayBufferMaxByteLength]].
1. Set |buffer|.\[[ArrayBufferData]] to |block|.
1. Set |buffer|.\[[ArrayBufferByteLength]] to the length of |block|.
1. Set |buffer|.\[[ArrayBufferMaxByteLength]] to |maxsize|.
1. Perform ! [$SetIntegrityLevel$](|buffer|, `"frozen"`).
1. Otherwise,
1. Let |buffer| be a new {{ArrayBuffer}} whose \[[ArrayBufferData]] is |block| and \[[ArrayBufferByteLength]] is set to the length of |block|.
1. Let |buffer| be a new {{ArrayBuffer}} with the internal slots \[[ArrayBufferData]], \[[ArrayBufferByteLength]], \[[ArrayBufferMaxByteLength]], and \[[ArrayBufferDetachKey]].
1. Set |buffer|.\[[ArrayBufferData]] to |block|.
1. Set |buffer|.\[[ArrayBufferByteLength]] to |length|.
1. Set |buffer|.\[[ArrayBufferMaxByteLength]] to |maxsize|.
1. Set |buffer|.\[[ArrayBufferDetachKey]] to "WebAssembly.Memory".
1. Return |buffer|.
</div>
Expand All @@ -623,7 +662,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
To <dfn>initialize a memory object</dfn> |memory| from a [=memory address=] |memaddr|, perform the following steps:
1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=].
1. Assert: |map|[|memaddr|] doesn't [=map/exist=].
1. Let |buffer| be the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|.
1. Let |buffer| be the result of [=create a fixed length memory buffer|creating a fixed length memory buffer=] from |memaddr|.
1. Set |memory|.\[[Memory]] to |memaddr|.
1. Set |memory|.\[[BufferObject]] to |buffer|.
1. [=map/Set=] |map|[|memaddr|] to |memory|.
Expand Down Expand Up @@ -655,39 +694,133 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
</div>

<div algorithm>
To <dfn>reset the Memory buffer</dfn> of |memaddr|, perform the following steps:
To <dfn>refresh the Memory buffer</dfn> of |memaddr|, perform the following steps:

1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=].
1. Assert: |map|[|memaddr|] [=map/exists=].
1. Let |memory| be |map|[|memaddr|].
1. If |memory|.\[[BufferObject]] is an {{ArrayBuffer}},
1. Perform [=!=] [$DetachArrayBuffer$](|memory|.\[[BufferObject]], "WebAssembly.Memory").
1. Let |buffer| be the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|.
1. Set |memory|.\[[BufferObject]] to |buffer|.
1. Let |buffer| be |memory|.\[[BufferObject]].
1. If [=IsFixedLengthArrayBuffer=](|buffer|) is true,
1. If |memory|.\[[BufferObject]] is an {{ArrayBuffer}},
1. Perform [=!=] [$DetachArrayBuffer$](|buffer|, "WebAssembly.Memory").
1. Let |buffer| be the result of [=create a fixed length memory buffer|creating a fixed length memory buffer=] from |memaddr|.
1. Set |memory|.\[[BufferObject]] to |buffer|.
1. Otherwise,
1. Let |block| be a [=Data Block=] which is [=identified with=] the underlying memory of |memaddr|.
1. Set |buffer|.\[[ArrayBufferData]] to |block|.
1. Set |buffer|.\[[ArrayBufferByteLength]] to the length of |block|.
</div>

<div algorithm=dom-Memory-grow>
The <dfn method for="Memory">grow(|delta|)</dfn> method, when invoked, performs the following steps:
<div algorithm>
To <dfn>grow the memory buffer</dfn> associated with a [=memory address=] |memaddr| by |delta|, perform the following steps:

1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1. Let |memaddr| be **this**.\[[Memory]].
1. Let |ret| be the [=mem_size=](|store|, |memaddr|).
1. Let |store| be [=mem_grow=](|store|, |memaddr|, |delta|).
1. If |store| is [=error=], throw a {{RangeError}} exception.
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
1. [=Reset the memory buffer=] of |memaddr|.
1. [=Refresh the memory buffer=] of |memaddr|.
1. Return |ret|.
</div>

<div algorithm=dom-Memory-grow>
The <dfn method for="Memory">grow(|delta|)</dfn> method, when invoked, performs the following steps:
1. Let |memaddr| be **this**.\[[Memory]].
1. Return the result of [=grow the memory buffer|growing the memory buffer=] associated with |memaddr| by |delta|.
</div>

Immediately after a WebAssembly [=memory.grow=] instruction executes, perform the following steps:

<div algorithm="memory.grow">
1. If the top of the stack is not [=i32.const=] (−1),
1. Let |frame| be the [=current frame=].
1. Assert: due to validation, |frame|.[=frame/module=].[=moduleinst/memaddrs=][0] exists.
1. Let |memaddr| be the memory address |frame|.[=frame/module=].[=moduleinst/memaddrs=][0].
1. [=Reset the memory buffer=] of |memaddr|.
1. [=Refresh the memory buffer=] of |memaddr|.
</div>

<div algorithm=dom-Memory-toFixedLengthBuffer>
The <dfn method for="Memory">toFixedLengthBuffer()</dfn> method, when invoked, performs the following steps:
1. Let |buffer| be **this**.\[[BufferObject]].
1. Let |memaddr| be **this**.\[[Memory]].
1. If |buffer| is an {{ArrayBuffer}},
1. If [=IsFixedLengthArrayBuffer=](|buffer|) is true, return |buffer|.
1. Otherwise,
1. Let |fixedBuffer| be the result of [=create a fixed length memory buffer|creating a fixed length memory buffer=] from |memaddr|.
1. Perform [=!=] [$DetachArrayBuffer$](|buffer|, "WebAssembly.Memory").
1. Set **this**.\[[BufferObject]] to |fixedBuffer|.
1. Return |fixedBuffer|.
1. Otherwise,
1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=].
1. Assert: |map|[|memaddr|] [=map/exists=].
1. Let |newMemory| be |map|[|memaddr|].
1. Let |newBufferObject| be |newMemory|.\[[BufferObject]].
1. Set **this**.\[[BufferObject]] to |newBufferObject|.
1. Return |newBufferObject|.
</div>

<div algorithm=dom-Memory-toResizableBuffer>
The <dfn method for="Memory">toResizableBuffer()</dfn> method, when invoked, performs the following steps:
1. Let |buffer| be **this**.\[[BufferObject]].
1. If [=IsFixedLengthArrayBuffer=](|buffer|) is false, return |buffer|.
1. Let |memaddr| be **this**.\[[Memory]].
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1. Let |memtype| be [=mem_type=](|store|, |memaddr|).
1. If |memtype| has a max,
1. Let |maxsize| be the max value in |memtype|.
1. Otherwise,
1. Let |maxsize| be 65536 &times; 65536.
1. Let |resizableBuffer| be the result of [=create a resizable memory buffer|creating a resizable memory buffer=] from |memaddr| and |maxsize|.
1. If |buffer| is an {{ArrayBuffer}},
1. Perform [=!=] [$DetachArrayBuffer$](|buffer|, "WebAssembly.Memory").
1. Set **this**.\[[BufferObject]] to |resizableBuffer|.
1. Return |resizableBuffer|.
</div>

{{ArrayBuffer}} and {{SharedArrayBuffer}} objects returned by a {{Memory}} object must have size that is a multiple of a WebAssembly [=page size=] (the constant 65536). For this reason [=HostResizeArrayBuffer=] and [=HostGrowSharedArrayBuffer=] are redefined as follows.

<div algorithm>
The <dfn>abstract operation [=HostResizeArrayBuffer=]</dfn> takes arguments an {{ArrayBuffer}} |buffer| and |newLength|. It performs the following steps when called.

1. If |buffer|.\[[ArrayBufferDetachKey]] is "WebAssembly.Memory",
1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=].
1. Assert: |buffer| is the \[[BufferObject]] of exactly one value in |map|.
1. [=map/iterate|For each=] |memaddr| &rarr; |mem| in |map|,
1. If [=SameValue=](mem.\[[BufferObject]], |buffer|) is true,
1. Assert: |buffer|.\[[ArrayBufferByteLength]] modulo 65536 is 0.
1. Let |lengthDelta| be |newLength| - |buffer|.\[[ArrayBufferByteLength]].
1. If |lengthDelta| &lt; 0 or |lengthDelta| modulo 65536 is not 0,
1. Throw a {{RangeError}} exception.
1. Let |delta| be |lengthDelta| &div; 65536.
1. [=grow the memory buffer|Grow the memory buffer=] associated with |memaddr| by |delta|.
1. Return handled.
1. Otherwise, return unhandled.
</div>

<div algorithm>
The <dfn>abstract operation [=HostGrowSharedArrayBuffer=]</dfn> takes arguments a {{SharedArrayBuffer}} |buffer| and |newLength|. It performs the following steps when called.

1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=].
1. Assert: |buffer| is the \[[BufferObject]] of exactly one value in |map|.
1. [=map/iterate|For each=] |memaddr| &rarr; |mem| in |map|,
1. If [=SameValue=](mem.\[[BufferObject]], |buffer|) is true,
1. Assert: |buffer|.\[[ArrayBufferByteLength]] modulo 65536 is 0.
1. Let |lengthDelta| be |newLength| - |buffer|.\[[ArrayBufferByteLength]].
1. If |lengthDelta| &lt; 0 or |lengthDelta| modulo 65536 is not 0,
1. Throw a {{RangeError}} exception.
1. Let |delta| be |lengthDelta| &div; 65536.
1. [=grow the memory buffer|Grow the memory buffer=] associated with |memaddr| by |delta|.
1. If |newLength| &lt; |buffer|.\[[ArrayBufferByteLength]] or |newLength| &gt; |buffer|.\[[ArrayBufferMaxByteLength]], throw a {{RangeError}} exception.
1. Let |agentRecord| be the surrounding agent's [=Agent Record=].
1. Let |isLittleEndian| be |agentRecord|.\[[LittleEndian]] .
1. Let |event| be an implementation defined [=ReadModifyWriteSharedMemory=] event, whose \[[Order]] is "SeqCst", \[[Payload]] is [§NumericToRawBytes$](Bigint, |newLength|, |isLittleEndian|), \[[Block]] is |buffer|.\[[ArrayBufferByteLengthData]], \[[ByteIndex]] is 0, and \[[ElementSize]] is 8.
1. Let |eventsRecord| be the [=Agent Events Record|EventsRecord=] in |agentRecord|.\[[CandidateExecution]].\[[EventsRecords]] that corresponds to the surrounding agent's signifier |agentRecord|.\[[Signifier]].
1. Append |event| to |eventsRecord|.\[[EventsList]].
1. Return handled.
</div>

Note: (TODO) Check the error case of memory.grow on the Wasm side.

<div algorithm>
The getter of the <dfn attribute for="Memory">buffer</dfn> attribute of {{Memory}} perfoms the following steps:

Expand Down