From a414dd885c9638b0db50073e89f71d7622a731a4 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Tue, 29 Jan 2019 11:03:11 -0800 Subject: [PATCH] Add JS API spec text (#116) In the overview, the `Memory.buffer` getter only creates a new `SharedArrayBuffer` when the lengths don't match. In the JS spec, there is a Memory object cache which is unconditionally updated with the most recent memory object and its length after every grow operation. So I think it makes sense to specify that the `buffer` getter always accesses this cache, since it is simpler (and unobservable, I think). --- document/js-api/index.bs | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index d708fb6419..6c5b2c71e7 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -28,6 +28,7 @@ Prepare For TR: true urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT type: interface; for: ECMAScript text: ArrayBuffer; url: sec-arraybuffer-objects + text: SharedArrayBuffer; url: sec-sharedarraybuffer-objects type: exception; for: ECMAScript text: Error; url: sec-error-objects text: NativeError; url: sec-nativeerror-constructors @@ -36,7 +37,9 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT type: dfn text: agent cluster; url: sec-agent-clusters text: agent; url: agent - text: data block; url: sec-data-blocks + url: sec-data-blocks + text: data block + text: shared data block text: Bound Function; url: sec-bound-function-exotic-objects text: NumericLiteral; url: sec-literals-numeric-literals text: surrounding agent; url: surrounding-agent @@ -537,12 +540,13 @@ interface Instance { dictionary MemoryDescriptor { required [EnforceRange] unsigned long initial; [EnforceRange] unsigned long maximum; + boolean shared = false; }; [LegacyNamespace=WebAssembly, Constructor(MemoryDescriptor descriptor), Exposed=(Window,Worker,Worklet)] interface Memory { unsigned long grow([EnforceRange] unsigned long delta); - readonly attribute ArrayBuffer buffer; + readonly attribute (ArrayBuffer or SharedArrayBuffer) buffer; }; @@ -552,15 +556,19 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each {{Memory}} object has the following internal slots: * \[[Memory]] : a [=memory address=] - * \[[BufferObject]] : an {{ArrayBuffer}} whose [=Data Block=] is [=identified with=] the above memory address + * \[[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: 1. Let |block| be a [=Data Block=] which is [=identified with=] the underlying memory of |memaddr|. - 1. Let |buffer| be a new {{ArrayBuffer}} whose \[[ArrayBufferData]] is |block| and \[[ArrayBufferByteLength]] is set to the length of |block|. - 1. Set |buffer|.\[[ArrayBufferDetachKey]] to "WebAssembly.Memory". + 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. 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. Set |buffer|.\[[ArrayBufferDetachKey]] to "WebAssembly.Memory". 1. Return |buffer|.
@@ -581,7 +589,9 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. let |initial| be |descriptor|["initial"]. 1. If |descriptor|["maximum"] is [=present=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. 1. If |maximum| is not empty and |maximum| < |initial|, throw a {{RangeError}} exception. - 1. Let |memtype| be { min |initial|, max |maximum| } + 1. Let |shared| be |descriptor|["shared"]. + 1. If |shared| is true and |maximum| is empty, throw a {{RangeError}} exception. + 1. Let |memtype| be { min |initial|, max |maximum|, shared |shared| } 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let (|store|, |memaddr|) be [=alloc_mem=](|store|, |memtype|). If allocation fails, throw a {{RangeError}} exception. 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. @@ -594,7 +604,8 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 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. Perform ! [=DetachArrayBuffer=](|memory|.\[[BufferObject]], "WebAssembly.Memory"). + 1. If |memory|.\[[BufferObject]] is an {{ArrayBuffer}}, + 1. Perform ! [=DetachArrayBuffer=](|memory|.\[[BufferObject]], "WebAssembly.Memory"). 1. Let |buffer| be a the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|. 1. Set |memory|.\[[BufferObject]] to |buffer|. @@ -623,7 +634,20 @@ Immediately after a WebAssembly [=memory.grow=] instruction executes, perform th
- The getter of the buffer attribute of {{Memory}} returns the receiver's \[[BufferObject]] internal slot. + The getter of the buffer attribute of {{Memory}} perfoms the following steps: + + 1. Let |memory| be the Memory instance. + 1. Let |memaddr| be |memory|.\[[Memory]]. + 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 |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 |memory|.\[[BufferObject]] to |newBufferObject|. + 1. Return |newBufferObject|. + 1. Otherwise, + 1. Return |memory|.\[[BufferObject]].

Tables