Skip to content

Commit

Permalink
Add JS API spec text (WebAssembly#116)
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
binji authored Jan 29, 2019
1 parent 0b80037 commit a414dd8
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions document/js-api/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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;
};
</pre>

Expand All @@ -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
</div>

<div algorithm>
To <dfn>create a 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. 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|.
</div>

Expand All @@ -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| &lt; |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|.
Expand All @@ -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|.
</div>
Expand Down Expand Up @@ -623,7 +634,20 @@ Immediately after a WebAssembly [=memory.grow=] instruction executes, perform th
</div>

<div algorithm>
The getter of the <dfn attribute for="Memory">buffer</dfn> attribute of {{Memory}} returns the receiver's \[[BufferObject]] internal slot.
The getter of the <dfn attribute for="Memory">buffer</dfn> 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]].
</div>

<h3 id="tables">Tables</h3>
Expand Down

0 comments on commit a414dd8

Please sign in to comment.