diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index ab1e6dbe1..683f4ffa7 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -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
@@ -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
@@ -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
@@ -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;
};
@@ -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
- To create a memory buffer from a [=memory address=] |memaddr|, perform the following steps:
+ To create a fixed length memory buffer 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|.
+
+
+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.
+
+
+ To create a resizable memory buffer 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| > (65536 × 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|.
@@ -623,7 +662,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
To initialize a memory object |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|.
@@ -655,29 +694,41 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
- To reset the Memory buffer of |memaddr|, perform the following steps:
+ To refresh the Memory buffer 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|.
-
- The
grow(|delta|) method, when invoked, performs the following steps:
+
+ To grow the memory buffer 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|.
+
+ The grow(|delta|) 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|.
+
+
Immediately after a WebAssembly [=memory.grow=] instruction executes, perform the following steps:
@@ -685,9 +736,91 @@ Immediately after a WebAssembly [=memory.grow=] instruction executes, perform th
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|.
+
+
+
+ The toFixedLengthBuffer() 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|.
+
+
+
+ The toResizableBuffer() 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 × 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|.
+
+
+{{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.
+
+
+ The abstract operation [=HostResizeArrayBuffer=] 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| → |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| < 0 or |lengthDelta| modulo 65536 is not 0,
+ 1. Throw a {{RangeError}} exception.
+ 1. Let |delta| be |lengthDelta| ÷ 65536.
+ 1. [=grow the memory buffer|Grow the memory buffer=] associated with |memaddr| by |delta|.
+ 1. Return handled.
+ 1. Otherwise, return unhandled.
+
+ The abstract operation [=HostGrowSharedArrayBuffer=] 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| → |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| < 0 or |lengthDelta| modulo 65536 is not 0,
+ 1. Throw a {{RangeError}} exception.
+ 1. Let |delta| be |lengthDelta| ÷ 65536.
+ 1. [=grow the memory buffer|Grow the memory buffer=] associated with |memaddr| by |delta|.
+ 1. If |newLength| < |buffer|.\[[ArrayBufferByteLength]] or |newLength| > |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.
+
+
+Note: (TODO) Check the error case of memory.grow on the Wasm side.
+
The getter of the buffer attribute of {{Memory}} perfoms the following steps: