Repository navigation
Expand file tree
/
Copy pathindex.md
More file actions
269 lines (197 loc) · 12.2 KB
/
Copy pathindex.md
File metadata and controls
269 lines (197 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
---
title: "elem: Wasm definition"
short-title: elem
slug: WebAssembly/Reference/Definitions/elem
page-type: webassembly-instruction
browser-compat: webassembly.definitions.elem
sidebar: webassemblysidebar
---
The **`elem`** [definition](/en-US/docs/WebAssembly/Reference/Definitions) declares an **element segment**, which is a series of references that can be copied into a Wasm [`table`](/en-US/docs/WebAssembly/Reference/Definitions/table). They provide a way to initialize a table on instantiation, analogous to [data segments](/en-US/docs/WebAssembly/Reference/Definitions/data) for Wasm [memories](/en-US/docs/WebAssembly/Reference/Definitions/memory).
{{InteractiveExample("Wat Demo: elem", "tabbed-taller")}}
```wat interactive-example
(module
;; table with 2 slots
(table $return_values 2 funcref)
;; Define functions
(func $f1 (result i32)
i32.const 42
)
(func $f2 (result i32)
i32.const 100
)
;; initialize table slots actively
(elem (table $return_values) (offset i32.const 0) func $f1 $f2)
(func (export "accessTable") (param $index i32) (result i32)
(local.get $index)
(call_indirect (result i32))
)
)
```
```js interactive-example
WebAssembly.instantiateStreaming(fetch("{%wasm-url%}")).then((result) => {
const value = result.instance.exports.accessTable(1);
console.log(value);
});
```
In the above example, we define a table with two slots, define two functions, then initialize the table immediately using an `elem` definition written in the active form, specifying the index value of the `table`. We then declare and export a function called `accessTable()`, which calls one of the functions referenced in our table, specifying the element number to call as its parameter. We invoke that function in JavaScript, then log the returned value to the console.
## Syntax
```plain
;; Active form, table initialized on instantiation
elem name table_identifier offset value_type element_list
;; Passive form, initialized later via table.init
elem name value_type element_list
;; Declarative form, declares already existing reference(s)
elem name declare value_type element_list
```
- `elem`
- : The `elem` definition type. Must always be included first.
- `name` {{optional_inline}}
- : An optional identifying name for the elem. This must begin with a `$` symbol, for example `$my_table`. If this is omitted, the `elem` can be identified (for example when calling `elem.drop`) by its index, for example `0` for the first `elem` in the wasm module, `1` for the second, etc.
- `table_identifier` {{optional_inline}}
- : An identifier representing the `table` instance to place the table elements into, which must be preceded by the `table` keyword to be interpreted as a `table_identifier`. This can be one of:
- `name`
- : An identifying name [set for the `table`](/en-US/docs/WebAssembly/Reference/Definitions/table#name) when it was first defined. This must begin with a `$` symbol and be preceded by a `table` keyword, for example `(table $my_table)`.
- `index`
- : An [`i32`](/en-US/docs/WebAssembly/Reference/Value_types/i32) value representing the index number of the table, for example `(table 0)` for the first table in the module, `(table 1)` for the second, etc.
> [!NOTE]
> When writing an active form `elem` definition, the `offset` must be included, but the `table_identifier` can be omitted, in which case it defaults to `(table 0)`.
- `offset` {{optional_inline}}
- : An integer representing the offset at which to start placing the elements into the `table`. This value can be any [constant expression](https://webassembly.github.io/spec/core/valid/instructions.html#valid-constant), meaning that it can include structures like arithmetic expressions as well as numeric values.
The full syntax includes the `offset` keyword before the value, for example `(offset i32.const 0)`, although the keyword can be omitted in the abbreviated form, for example `(i32.const 0)`.
- `declare` {{optional_inline}}
- : A keyword that identifies the `elem` definition as being of the declarative form, meaning that it declares references that will be used at runtime (for example, by `ref.func`), without them being inserted into a table.
- `value_type`
- : A value type that defines which type of reference will be stored in this table. All references in the `element_list` must match this type. The value can be any reference type, such as:
- `func`
- : An abbreviation that more concisely declares a list of non-nullable function references. For example `func $my_func` is equivalent to `(ref func) (ref.func $my_func)`.
- [`funcref`](/en-US/docs/WebAssembly/Reference/Value_types/funcref)
- : Function references, for example `(ref.func $my_func)`, `(ref null func)`, `(ref func)`.
- [`externref`](/en-US/docs/WebAssembly/Reference/Value_types/externref)
- : External value references, for example `(ref.null extern)`, `(ref null extern)`.
- [`exnref`](/en-US/docs/WebAssembly/Reference/Value_types/exnref)
- : Exception references, for example `(ref.null extern)`.
- `eqref`, `structref`, `arrayref`, `anyref`
- : References to garbage collection (GC) values.
- `nullref`, `nullfuncref`, `nullexternref`
- : Null references.
- `element_list`
- : A space-separated list of references to be stored in the `table`.
## Description
Wasm `elem` definitions define a series of references. There are three forms of `elem` definition:
- [Active form](#active_form)
- [Passive form](#passive_form)
- [Declarative form](#declarative_form)
### Active form
An active element definition is used to define an element segment that is immediately written into a previously-defined [`table`](/en-US/docs/WebAssembly/Reference/Definitions/table) on instantiation and then discarded. In active form, a table first needs to be defined:
```wat
(table $return_values 2 funcref)
```
You then declare an `elem` definition that includes the references to store. In this case, we are storing function references in the `table`:
```wat
(func $f1 (result i32)
i32.const 42
)
(func $f2 (result i32)
i32.const 100
)
(elem (table $return_values) (i32.const 0) func $f1 $f2)
```
This `elem` definition includes the `value_type` to be stored (`func`), and the `element_list` to store in the table (`$f1 $f2`). Most significantly, it includes a number indicating the offset to start writing the references at — `(i32.const 0)` — which indicates the first slot of the table.
We've also included a `table_identifier` — `(table $return_values)` — to indicate the table to write the references to, although in this basic example there is only one table, so this is not necessary.
> [!NOTE]
> Active `elem` segments are dropped automatically during module instantiation, and therefore are not available to drop via [`elem.drop`](/en-US/docs/WebAssembly/Reference/Elem/drop).
### Passive form
In passive form, the `elem` definition declares the references that should be stored in the table in the same way as in active form. The main difference is that, in passive form, you don't specify the `table_identifier` or `offset` value. This means that the references are not stored in the `table` immediately. Instead, this part of the process is handled manually using a [`table.init`](/en-US/docs/WebAssembly/Reference/Table/init) instruction.
Let's see what this looks like in code. We include the `elem` definition in a similar manner to the active form example, except that this time we don't include the `table_identifier`. Instead, we include a `name` value (`$funcs`) to identify the `elem` later on.
```wat
(elem $funcs funcref (ref.func $f1) (ref.func $f2))
```
We can then call `table.init`, referencing the `elem` `name`, to copy the references into the specified table:
```wat
(func (export "init")
i32.const 0 ;; destination table index
i32.const 0 ;; offset into elem segment
i32.const 2 ;; number of elements to copy
table.init $funcs
)
```
After `table.init` has been called, the `elem` segment is no longer needed, so [`elem.drop`](/en-US/docs/WebAssembly/Reference/Elem/drop) can be called to free up the memory it was using:
```wat
elem.drop $funcs
```
> [!NOTE]
> You can see a full working example at [Passive `elem` example](#passive_elem_example).
### Declarative form
The declarative form of `elem` is used when you want to use a reference in your code without putting it into a table. It allows you to create a reference that can be referenced via `ref.func`:
```wat
(module
;; Create a reference to the $add function
(elem declare func $add)
(func $add (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add
)
(func (export "getRef") (result funcref)
;; only valid because of the declarative elem above
ref.func $add
)
)
```
This was added to the language because normally you can only reference functions with `ref.func` that have been made referenceable, for example in a [`global`](/en-US/docs/WebAssembly/Reference/Definitions/global) definition or by being imported from the JavaScript host. Declarative `elem` definitions exist to make some functions referenceable that otherwise wouldn't be.
## Examples
### Passive `elem` example
This example shows how you can use the passive form of `elem` to defer copying the specified references to the table on instantiation, later adding them using the [`table.init`](/en-US/docs/WebAssembly/Reference/Table/init) instruction.
#### JavaScript
In our script, we start by grabbing a reference to a {{htmlelement("p")}} element that we will output results to. We then compile and instantiate our Wasm module using the [`WebAssembly.instantiateStreaming()`](/en-US/docs/WebAssembly/Reference/JavaScript_interface/instantiateStreaming_static) method. When the result is returned, we invoke the exported Wasm `init()` function (which as you'll see later, runs `table.init`), then run the exported `accessTable()` function, passing it the number `0` as a parameter. Finally, we set the `accessTable()` function's return value to the `<p>` element's `textContent` value so we can inspect it.
```html hidden live-sample___basic-usage
<p></p>
```
```js live-sample___basic-usage
const output = document.querySelector("p");
WebAssembly.instantiateStreaming(fetch("{%wasm-url%}")).then((result) => {
result.instance.exports.init();
const value = result.instance.exports.accessTable(1);
output.textContent = value;
});
```
#### Wasm
In our Wasm module, we first define a `table` with two slots, then define two functions called `$f1` and `$f2`, which return the values defined within. Next, we include an `elem` definition called `$funcs`, which references the `$f1` and `$f2` functions.
Finally, we export two functions:
- `init()`: Runs a `table.init` instruction to store the functions referenced in the `$funcs` `elem` in the `table`.
- `accessTable()`: Takes an `i32` named `$index` as a parameter, and returns an `i32`. Inside the function body, we use `call_indirect` to call the function referenced in the table at the index value `$index`.
```wat live-sample___basic-usage
(module
(table $return_values 2 funcref)
(func $f1 (result i32)
i32.const 42
)
(func $f2 (result i32)
i32.const 100
)
(elem $funcs funcref (ref.func $f1) (ref.func $f2))
(func (export "init")
i32.const 0 ;; destination table index
i32.const 0 ;; offset into elem segment
i32.const 2 ;; number of elements to copy
table.init $funcs
)
(func (export "accessTable") (param $index i32) (result i32)
local.get $index
call_indirect (result i32)
)
)
```
#### Result
The outputted value is as follows:
{{embedlivesample("basic-usage", "100%", 100)}}
This makes sense, as the exported `accessTable()` function has an index value passed into it. Inside the Wasm module, we call the function available at that index in the defined table, which returns the value we see output.
Note that we have to call `init()` before we call `accessTable()`, to initialize the table with references. If we didn't do that, the program would error.
## Specifications
{{Specifications}}
## Browser compatibility
{{Compat}}
## See also
- [`elem.drop`](/en-US/docs/WebAssembly/Reference/Elem/drop) instruction
- [`table`](/en-US/docs/WebAssembly/Reference/Definitions/table) definition
- [WebAssembly table instructions](/en-US/docs/WebAssembly/Reference/Table)