-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update proposal to include {mem,table}.drop #85
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,17 +74,29 @@ requires two modules where one should be enough. | |
|
||
## Proposal: New instructions to initialize data and element segments | ||
|
||
Similar to solution 2, we repurpose the memory index as a flags field. Unlike | ||
solution 2, the flags field specifies whether this segment is _inactive_. An | ||
inactive segment will not be automatically copied into the memory or table on | ||
instantiation, and must instead be applied manually using two new instructions: | ||
`init_memory` and `init_table`. | ||
The [binary format for the data section](https://webassembly.github.io/spec/binary/modules.html#data-section) | ||
currently has a collection of segments, each of which has a memory index, an | ||
initializer expression for its offset, and its raw data. | ||
|
||
When the least-significant bit of the flags field is `1`, the segment is | ||
inactive. The rest of the bits of the flags field must be zero. | ||
Since WebAssembly currently does not allow for multiple memories, the memory | ||
index must be zero. We can repurpose this field as a flags field. | ||
|
||
When the least-significant bit of the flags field is `1`, this segment is | ||
_inactive_. An inactive segment will not be automatically copied into the | ||
memory or table on instantiation, and must instead be applied manually using | ||
the following new instructions: | ||
|
||
* `mem.init`: copy a region from a data segment | ||
* `table.init`: copy an region from an element segment | ||
|
||
An inactive segment has no initializer expression, since it will be specified | ||
as an operand to `init_memory` or `init_table`. | ||
as an operand to `mem.init` or `table.init`. | ||
|
||
Segments (either active or inactive) can also be discarded by using the | ||
following new instructions: | ||
|
||
* `mem.drop`: prevent further use of a data segment | ||
* `table.drop`: prevent further use of an element segment | ||
|
||
The data section is encoded as follows: | ||
|
||
|
@@ -96,36 +108,41 @@ data ::= 0x01 b*:vec(byte) => {data 0, offset empty, init b*, acti | |
|
||
The element section is encoded similarly. | ||
|
||
### `init_memory` instruction | ||
### `mem.init` instruction | ||
|
||
The `init_memory` instruction copies data from a given segment into a target | ||
The `mem.init` instruction copies data from a given segment into a target | ||
memory. The source segment and target memory are given as immediates. The | ||
instruction also has three i32 operands: an offset into the source segment, an | ||
offset into the target memory, and a length to copy. | ||
|
||
When `init_memory` is executed, its behavior matches the steps described in | ||
When `mem.init` is executed, its behavior matches the steps described in | ||
step 11 of | ||
[instantiation](https://webassembly.github.io/spec/exec/modules.html#instantiation), | ||
but it behaves as though the segment were specified with the source offset, | ||
target offset, and length as given by the `init_memory` operands. | ||
|
||
`init_memory` may only be used during | ||
[instantiation](https://webassembly.github.io/spec/exec/modules.html#instantiation) | ||
when the start function is being invoked. At any other times, the instructions | ||
will trap. | ||
target offset, and length as given by the `mem.init` operands. | ||
|
||
A trap occurs if any of the accessed bytes lies outside the source data segment | ||
or the target memory. | ||
or the target memory. A trap also occurs if the segment is used after it has | ||
been dropped via `mem.drop`. | ||
|
||
Note that it is allowed to use `init_memory` on the same data segment more than | ||
Note that it is allowed to use `mem.init` on the same data segment more than | ||
once, or with an active data segment. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's a mistake to allow mem.init to be used with an active data segment. The current contract is that the active data segment may be dropped by the implementation once the Module object becomes GC-able. This makes mem.init sensitive to GC timing, because it'll have to trap if the data segment has been removed. IMO all the programmatic mem opcodes should only be usable with the inactive data segments. (I also have decided I dislike the terminology "active" and "inactive", but I've been at a loss to propose something better. Still am, really. But "instantiation-time" vs "run-time" would capture the distinction better.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I think you're right. I'll try to find some time to update before the end of the year... (at home with the family 😄). |
||
|
||
### `init_table` instruction | ||
### `mem.drop` instruction | ||
|
||
The `init_table` instruction behaves similary to the `init_memory` instruction, | ||
with the difference that it operates on element segments and tables, instead of | ||
data segments and memories. The offset and length operands of `init_table` have | ||
element units instead of bytes as well. | ||
The `mem.drop` instruction prevents further use of a given segment. After a | ||
data segment has been dropped, it is no longer valid to use it in a `mem.init` | ||
instruction. This instruction is intended to be used as an optimization hint to | ||
the WebAssembly implementation. After a memory segment is dropped its data can | ||
no longer be retrieved, so the memory used by this segment may be freed. | ||
|
||
### `table.init` and `table.drop` instructions | ||
|
||
The `table.init` and `table.drop` instructions behave similary to the | ||
`mem.init` and `mem.drop` instructions, with the difference that they operate | ||
on element segments and tables, instead of data segments and memories. The | ||
offset and length operands of `table.init` have element units instead of bytes | ||
as well. | ||
|
||
### Example | ||
|
||
|
@@ -141,10 +158,15 @@ non-zero value. This could be implemented as follows: | |
|
||
(func $start | ||
(if (get_global 0) | ||
|
||
;; copy data segment 1 into memory | ||
(init_memory 1 | ||
(mem.init 1 | ||
(i32.const 0) ;; source offset | ||
(i32.const 16) ;; target offset | ||
(i32.const 7))) ;; length | ||
(i32.const 7)) ;; length | ||
|
||
;; The memory used by this segment is no longer needed, so this segment can | ||
;; be dropped. | ||
(mem.drop 1)) | ||
) | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gosh, I'm not sure if it's a good idea to be able to drop active memories. Suppose you can, and do. Then you instantiate the module again. What happens then? A trap? (That would be the interpretation of the prose further down.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wasn't sure about this one. I was thinking it would be a nice optimization to be able to discard to active segments (say, if you know that there will never be another instance), but perhaps we should be more conservative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd err on the side of conservative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, changed.