Skip to content
This repository was archived by the owner on Nov 3, 2021. It is now read-only.

Commit 096ac5b

Browse files
authored
Include ConditionalSegmentInitialization proposal (#4)
1 parent 1efc603 commit 096ac5b

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ and `memset`) to WebAssembly.
1010
See the [overview](proposals/bulk-memory-operations/Overview.md) for a summary of the
1111
proposal.
1212

13+
This proposal also includes functionality to conditionally initialize data and
14+
elem segments that was previously coupled with the
15+
[thread proposal](https://github.com/WebAssembly/threads). This is currently in a
16+
[separate overview document](proposals/bulk-memory-operations/ConditionalSegmentInitialization.md)
17+
but will combined into the main overview soon.
18+
1319
Original README from upstream repository follows...
1420

1521
# spec
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# Proposal to conditionally initialize segments
2+
3+
This page describes a proposal for providing a mechanism to skip data or
4+
element segment initialization when instantiating a module.
5+
6+
Although the following rationale applies only to data segments, this proposal
7+
suggests that the proposed solutions apply to element segments as well for
8+
consistency.
9+
10+
## Rationale
11+
12+
Under the current threading proposal, to share a module between multiple
13+
agents, the module must be instantiated multiple times: once per agent.
14+
Instantiation initializes linear memory with the contents in the module's data
15+
segments. If the memory is shared between multiple agents, it will be
16+
initialized multiple times, potentially overwriting stores that occurred after
17+
the previous initializations.
18+
19+
For example:
20+
21+
```webassembly
22+
;; The module.
23+
(module
24+
(memory (export "memory") 1)
25+
26+
;; Some value used as a counter.
27+
(data (i32.const 0) "\0")
28+
29+
;; Add one to the counter.
30+
(func (export "addOne")
31+
(i32.store8
32+
(i32.const 0)
33+
(i32.add
34+
(i32.load8_u (i32.const 0))
35+
(i32.const 1)))
36+
)
37+
)
38+
```
39+
40+
```javascript
41+
// main.js
42+
let moduleBytes = ...;
43+
44+
WebAssembly.instantiate(moduleBytes).then(
45+
({module, instance}) => {
46+
// Increment our counter.
47+
instance.exports.addOne();
48+
49+
// Spawn a new Worker.
50+
let worker = new Worker('worker.js');
51+
52+
// Send the module to the new Worker.
53+
worker.postMessage(module);
54+
});
55+
56+
// worker.js
57+
58+
function onmessage(event) {
59+
let module = event.data;
60+
61+
// Use the module to create another instance.
62+
WebAssembly.instantiate(module).then(
63+
(instance) => {
64+
// Oops, our counter has been clobbered.
65+
});
66+
}
67+
68+
```
69+
70+
This can be worked around by storing the data segments in a separate module
71+
which is only instantiated once, then exporting this memory to be used by
72+
another module that contains only code. This works, but it cumbersome since it
73+
requires two modules where one should be enough.
74+
75+
## Proposal: New instructions to initialize data and element segments
76+
77+
The [binary format for the data section](https://webassembly.github.io/spec/binary/modules.html#data-section)
78+
currently has a collection of segments, each of which has a memory index, an
79+
initializer expression for its offset, and its raw data.
80+
81+
Since WebAssembly currently does not allow for multiple memories, the memory
82+
index must be zero. We can repurpose this field as a flags field.
83+
84+
When the least-significant bit of the flags field is `1`, this segment is
85+
_passive_. A passive segment will not be automatically copied into the
86+
memory or table on instantiation, and must instead be applied manually using
87+
the following new instructions:
88+
89+
* `mem.init`: copy a region from a data segment
90+
* `table.init`: copy an region from an element segment
91+
92+
An passive segment has no initializer expression, since it will be specified
93+
as an operand to `mem.init` or `table.init`.
94+
95+
Passive segments can also be discarded by using the following new instructions:
96+
97+
* `mem.drop`: prevent further use of a data segment
98+
* `table.drop`: prevent further use of an element segment
99+
100+
Attempting to drop an active segment is a validation error.
101+
102+
The data section is encoded as follows:
103+
104+
```
105+
datasec ::= seg*:section_11(vec(data)) => seg
106+
data ::= 0x00 e:expr b*:vec(byte) => {data 0, offset e, init b*, active true}
107+
data ::= 0x01 b*:vec(byte) => {data 0, offset empty, init b*, active false}
108+
```
109+
110+
The element section is encoded similarly.
111+
112+
### `mem.init` instruction
113+
114+
The `mem.init` instruction copies data from a given passive segment into a target
115+
memory. The source segment and target memory are given as immediates. The
116+
instruction also has three i32 operands: an offset into the source segment, an
117+
offset into the target memory, and a length to copy.
118+
119+
When `mem.init` is executed, its behavior matches the steps described in
120+
step 11 of
121+
[instantiation](https://webassembly.github.io/spec/exec/modules.html#instantiation),
122+
but it behaves as though the segment were specified with the source offset,
123+
target offset, and length as given by the `mem.init` operands.
124+
125+
A trap occurs if:
126+
* the segment is passive
127+
* the segment is used after it has been dropped via `mem.drop`
128+
* any of the accessed bytes lies outside the source data segment or the target memory
129+
130+
Note that it is allowed to use `mem.init` on the same data segment more than
131+
once.
132+
133+
### `mem.drop` instruction
134+
135+
The `mem.drop` instruction prevents further use of a given segment. After a
136+
data segment has been dropped, it is no longer valid to use it in a `mem.init`
137+
instruction. This instruction is intended to be used as an optimization hint to
138+
the WebAssembly implementation. After a memory segment is dropped its data can
139+
no longer be retrieved, so the memory used by this segment may be freed.
140+
141+
### `table.init` and `table.drop` instructions
142+
143+
The `table.init` and `table.drop` instructions behave similary to the
144+
`mem.init` and `mem.drop` instructions, with the difference that they operate
145+
on element segments and tables, instead of data segments and memories. The
146+
offset and length operands of `table.init` have element units instead of bytes
147+
as well.
148+
149+
### Example
150+
151+
Consider if there are two data sections, the first is always active and the
152+
second is conditionally active if global 0 has a non-zero value. This could be
153+
implemented as follows:
154+
155+
```webassembly
156+
(import "a" "global" (global i32)) ;; global 0
157+
(memory 1)
158+
(data (i32.const 0) "hello") ;; data segment 0, is active so always copied
159+
(data passive "goodbye") ;; data segment 1, is passive
160+
161+
(func $start
162+
(if (get_global 0)
163+
164+
;; copy data segment 1 into memory
165+
(mem.init 1
166+
(i32.const 0) ;; source offset
167+
(i32.const 16) ;; target offset
168+
(i32.const 7)) ;; length
169+
170+
;; The memory used by this segment is no longer needed, so this segment can
171+
;; be dropped.
172+
(mem.drop 1))
173+
)
174+
```

0 commit comments

Comments
 (0)